
kibana
Web Scraper + Elasticsearch + Kibana + SearchKit 打造的豆瓣电影top250 搜索演示系统
Elasticsearch • 森 发表了文章 • 0 个评论 • 4517 次浏览 • 2023-04-09 10:56
Web Scraper + Elasticsearch + Kibana + SearchKit 打造的豆瓣电影top250 搜索演示系统
作者:小森同学
声明:电影数据来源于“豆瓣电影”,如有侵权,请联系删除
Web Scraper
{
"_id": "top250",
"startUrl": ["https://movie.douban.com/top250?start=[0-225:25]&filter="],
"selectors": [{
"id": "container",
"multiple": true,
"parentSelectors": ["_root"],
"selector": ".grid_view li",
"type": "SelectorElement"
}, {
"id": "name",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "span.title:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "number",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "em",
"type": "SelectorText"
}, {
"id": "score",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "span.rating_num",
"type": "SelectorText"
}, {
"id": "review",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "span.inq",
"type": "SelectorText"
}, {
"id": "year",
"multiple": false,
"parentSelectors": ["container"],
"regex": "\\d{4}",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "tour_guide",
"multiple": false,
"parentSelectors": ["container"],
"regex": "^导演: \\S*",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "type",
"multiple": false,
"parentSelectors": ["container"],
"regex": "[^/]+$",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "area",
"multiple": false,
"parentSelectors": ["container"],
"regex": "[^\\/]+(?=\\/[^\\/]*$)",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "detail_link",
"multiple": false,
"parentSelectors": ["container"],
"selector": ".hd a",
"type": "SelectorLink"
}, {
"id": "director",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "",
"selector": "span:nth-of-type(1) .attrs a",
"type": "SelectorText"
}, {
"id": "screenwriter",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=编剧: )[\\u4e00-\\u9fa5A-Za-z0-9/()\\·\\s]+(?=主演)",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "film_length",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "\\d+",
"selector": "span[property='v:runtime']",
"type": "SelectorText"
}, {
"id": "IMDb",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=[IMDb:\\s+])\\S*(?=\\d*$)",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "language",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=语言: )\\S+",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "alias",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=又名: )[\\u4e00-\\u9fa5A-Za-z0-9/()\\s]+(?=IMDb)",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "pic",
"multiple": false,
"parentSelectors": ["container"],
"selector": "img",
"type": "SelectorImage"
}]
}
elasticsearch
{
"mappings": {
"properties": {
"IMDb": {
"type": "keyword",
"copy_to": [
"all"
]
},
"alias": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"all": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"area": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"director": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"film_length": {
"type": "long"
},
"id": {
"type": "keyword"
},
"language": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"link": {
"type": "keyword"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"number": {
"type": "long"
},
"photo": {
"type": "keyword"
},
"review": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"score": {
"type": "double"
},
"screenwriter": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"type": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"year": {
"type": "long"
}
}
}
}
kibana
需要使用pipeline对索引字段进行处理,如对type 通过空格进行分割为数组等,可以参照官方文档或其他博客。
制作仪表板省略, 请自行搜索
SearchKit
kibana搜索10000条输入限制如何解除
回复Kibana • onionwithhoney 发起了问题 • 1 人关注 • 0 个回复 • 4966 次浏览 • 2023-01-05 15:02
怎么查看 Kibana dashboard中最终执行的query语句
Kibana • sdx 回复了问题 • 2 人关注 • 1 个回复 • 989 次浏览 • 2022-07-08 11:19
在 Kibana 里统一访问来自不同集群的索引
资料分享 • medcl 发表了文章 • 0 个评论 • 1370 次浏览 • 2022-04-21 15:29
在 Kibana 里统一访问来自不同集群的索引
现在有这么一个需求,客户根据需要将数据按照业务维度划分,将索引分别存放在了不同的三个集群, 将一个大集群拆分成多个小集群有很多好处,比如降低了耦合,带来了集群可用性和稳定性方面的好处,也避免了单个业务的热点访问造成其他业务的影响, 尽管拆分集群是很常见的玩法,但是管理起来不是那么方便了,尤其是在查询的时候,可能要分别访问三套集群各自的 API,甚至要切换三套不同的 Kibana 来访问集群的数据, 那么有没有办法将他们无缝的联合在一起呢?
极限网关!
答案自然是有的,通过将 Kibana 访问 Elasticsearch 的地址切换为极限网关的地址,我们可以将请求按照索引来进行智能的路由, 也就是当访问不同的业务索引时会智能的路由到不同的集群,如下图:
上图,我们分别有 3 个不同的索引:
- apm-*
- erp-*
- mall-*
分别对应不同的三套 Elasticsearch 集群:
- ES1-APM
- ES2-ERP
- ES3-MALL
接下来我们来看如何在极限网关里面进行相应的配置来满足这个业务需求。
配置集群信息
首先配置 3 个集群的连接信息。
elasticsearch:
- name: es1-apm
enabled: true
endpoints:
- http://192.168.3.188:9206
- name: es2-erp
enabled: true
endpoints:
- http://192.168.3.188:9207
- name: es3-mall
enabled: true
endpoints:
- http://192.168.3.188:9208
配置服务 Flow
然后,我们定义 3 个 Flow,分别对应用来访问 3 个不同的 Elasticsearch 集群,如下:
flow:
- name: es1-flow
filter:
- elasticsearch:
elasticsearch: es1-apm
- name: es2-flow
filter:
- elasticsearch:
elasticsearch: es2-erp
- name: es3-flow
filter:
- elasticsearch:
elasticsearch: es3-mall
然后再定义一个 flow 用来进行路径的判断和转发,如下:
- name: default-flow
filter:
- switch:
remove_prefix: false
path_rules:
- prefix: apm-
flow: es1-flow
- prefix: erp-
flow: es2-flow
- prefix: mall-
flow: es3-flow
- flow: #default flow
flows:
- es1-flow
根据请求路径里面的索引前缀来匹配不同的索引,并转发到不同的 Flow。
配置路由信息
接下来,我们定义路由信息,具体配置如下:
router:
- name: my_router
default_flow: default-flow
指向上面定义的默认 flow 来统一请求的处理。
定义服务及关联路由
最后,我们定义一个监听为 8000 端口的服务,用来提供给 Kibana 来进行统一的入口访问,如下:
entry:
- name: es_entry
enabled: true
router: my_router
max_concurrency: 10000
network:
binding: 0.0.0.0:8000
完整配置
最后的完整配置如下:
path.data: data
path.logs: log
entry:
- name: es_entry
enabled: true
router: my_router
max_concurrency: 10000
network:
binding: 0.0.0.0:8000
flow:
- name: default-flow
filter:
- switch:
remove_prefix: false
path_rules:
- prefix: apm-
flow: es1-flow
- prefix: erp-
flow: es2-flow
- prefix: mall-
flow: es3-flow
- flow: #default flow
flows:
- es1-flow
- name: es1-flow
filter:
- elasticsearch:
elasticsearch: es1-apm
- name: es2-flow
filter:
- elasticsearch:
elasticsearch: es2-erp
- name: es3-flow
filter:
- elasticsearch:
elasticsearch: es3-mall
router:
- name: my_router
default_flow: default-flow
elasticsearch:
- name: es1-apm
enabled: true
endpoints:
- http://192.168.3.188:9206
- name: es2-erp
enabled: true
endpoints:
- http://192.168.3.188:9207
- name: es3-mall
enabled: true
endpoints:
- http://192.168.3.188:9208
启动网关
直接启动网关,如下:
➜ gateway git:(master) ✗ ./bin/gateway -config sample-configs/elasticsearch-route-by-index.yml
___ _ _____ __ __ __ _
/ _ \ /_\ /__ \/__\/ / /\ \ \/_\ /\_/\
/ /_\///_\\ / /\/_\ \ \/ \/ //_\\\_ _/
/ /_\\/ _ \/ / //__ \ /\ / _ \/ \
\____/\_/ \_/\/ \__/ \/ \/\_/ \_/\_/
[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2022-04-20 08:23:56, 2023-12-31 10:10:10, 51650a5c3d6aaa436f3c8a8828ea74894c3524b9
[04-21 13:41:21] [INF] [app.go:174] initializing gateway.
[04-21 13:41:21] [INF] [app.go:175] using config: /Users/medcl/go/src/infini.sh/gateway/sample-configs/elasticsearch-route-by-index.yml.
[04-21 13:41:21] [INF] [instance.go:72] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/c9bpg0ai4h931o4ngs3g
[04-21 13:41:21] [INF] [app.go:283] gateway is up and running now.
[04-21 13:41:21] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es1-apm] hosts: [] => [192.168.3.188:9206]
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es2-erp] hosts: [] => [192.168.3.188:9207]
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es3-mall] hosts: [] => [192.168.3.188:9208]
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es2-erp] is available
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es1-apm] is available
[04-21 13:41:21] [INF] [entry.go:312] entry [es_entry] listen at: http://0.0.0.0:8000
[04-21 13:41:21] [INF] [module.go:116] all modules are started
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es3-mall] is available
[04-21 13:41:55] [INF] [reverseproxy.go:255] elasticsearch [es1-apm] hosts: [] => [192.168.3.188:9206]
网关启动成功之后,就可以通过网关的 IP+8000 端口来访问目标 Elasticsearch 集群了。
测试访问
首先通过 API 来访问测试一下,如下:
➜ ~ curl http://localhost:8000/apm-2022/_search -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /apm-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 05:45:44 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 162
< X-elastic-product: Elasticsearch
< X-Backend-Cluster: es1-apm
< X-Backend-Server: 192.168.3.188:9206
< X-Filters: filters->elasticsearch
<
* Connection #0 to host localhost left intact
{"took":142,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}%
可以看到 apm-2022 指向了后端的 es1-apm
集群。
继续测试,erp 索引的访问,如下:
➜ ~ curl http://localhost:8000/erp-2022/_search -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /erp-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 06:24:46 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 161
< X-Backend-Cluster: es2-erp
< X-Backend-Server: 192.168.3.188:9207
< X-Filters: filters->switch->filters->elasticsearch->skipped
<
* Connection #0 to host localhost left intact
{"took":12,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}%
继续测试,mall 索引的访问,如下:
➜ ~ curl http://localhost:8000/mall-2022/_search -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /mall-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 06:25:08 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 134
< X-Backend-Cluster: es3-mall
< X-Backend-Server: 192.168.3.188:9208
< X-Filters: filters->switch->filters->elasticsearch->skipped
<
* Connection #0 to host localhost left intact
{"took":8,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}%
完美转发。
修改 Kibana 配置
修改 Kibana 的配置文件: kibana.yml
,替换 Elasticsearch 的地址为网关地址(http://192.168.3.200:8000
),如下:
elasticsearch.hosts: ["http://192.168.3.200:8000"]
重启 Kibana 让配置生效。
效果如下
可以看到,在一个 Kibana 的开发者工具里面,我们已经可以像操作一个集群一样来同时读写实际上来自三个不同集群的索引数据了。
展望
通过极限网关,我们还可以非常灵活的进行在线请求的流量编辑,动态组合不同集群的操作。
使用极限网关来代理 Kibana
Kibana • medcl 发表了文章 • 0 个评论 • 1567 次浏览 • 2022-02-15 20:29
entry:
- name: my_es_entry
enabled: true
router: my_router
max_concurrency: 10000
network:
binding: 0.0.0.0:8000
skip_occupied_port: true
tls:
enabled: true
flow:
- name: default_flow
filter:
- basic_auth:
valid_users:
medcl: passwd
- http:
schema: "http" #https or http
host: "192.168.3.98:5601"
router:
- name: my_router
default_flow: default_flow
修改里面的 ip 为你实际的 Kibana IP 地址,如需多个,使用 hosts 参数,详见文档手册:
https://极限网关.com/docs/references/filters/http/
启动网关,因为自动开启了 https,访问网关的服务地址:https://localhost:8000,如下:
输入配置的用户名密码,即可。
Elastic日报 第1307期 (2021-01-12)
Elastic日报 • kin122 发表了文章 • 0 个评论 • 935 次浏览 • 2022-01-12 10:13
Elastic日报 第1245期 (2021-11-10)
Elastic日报 • kin122 发表了文章 • 0 个评论 • 896 次浏览 • 2021-11-10 09:41
kibana7.14配置索引模式权限后页面依旧可以看到
Kibana • caster_QL 回复了问题 • 1 人关注 • 1 个回复 • 1504 次浏览 • 2021-09-30 18:26
kibana 7.14 本地开发模式提示crash
Kibana • tongchuan1992 回复了问题 • 2 人关注 • 1 个回复 • 1639 次浏览 • 2021-09-07 10:46
堆栈监测 监测beats bug有人遇到过吗
Kibana • tongchuan1992 回复了问题 • 2 人关注 • 1 个回复 • 1542 次浏览 • 2021-07-08 08:47
kibana如何才能使用nested的字段作为可视化的条件?
Kibana • liuxg 回复了问题 • 2 人关注 • 1 个回复 • 1524 次浏览 • 2021-07-02 10:01
kibana如何做出只查询出自己创建的索引的?
回复Elasticsearch • startjava 发起了问题 • 1 人关注 • 0 个回复 • 1556 次浏览 • 2021-07-01 16:04
新人求教,新安装的kibana,启动成功后访问不了
Kibana • Sanri99 回复了问题 • 3 人关注 • 2 个回复 • 16376 次浏览 • 2021-05-08 16:15
kibana中dashboard怎么复制使用
Kibana • Reilee 回复了问题 • 3 人关注 • 1 个回复 • 2440 次浏览 • 2021-01-26 06:28
Kibana 支持vega,可以试一试,而且时间全局过滤器也是可用的。
Kibana 支持vega,可以试一试,而且时间全局过滤器也是可用的。
【线下活动-分享主题征集-武汉】 2019年3月 Elastic&尚德机构技术沙龙
活动 • medcl 回复了问题 • 3 人关注 • 1 个回复 • 5340 次浏览 • 2019-02-22 15:42
使用 Elastic Stack 来监控和调优 Golang 应用程序
Beats • medcl 发表了文章 • 0 个评论 • 11220 次浏览 • 2017-03-03 11:16
- Apache Module
- Couchbase Module
- Docker Module
- HAProxy Module
- kafka Module
- MongoDB Module
- MySQL Module
- Nginx Module
- PostgreSQL Module
- Prometheus Module
- Redis Module
- System Module
- ZooKeeper Module
import _ "expvar"
如果 Golang 没有启动 http 服务,使用下面的方式启动一个即可,这里端口是 6060,如下:func metricsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
first := true
report := func(key string, value interface{}) {
if !first {
fmt.Fprintf(w, ",\n")
}
first = false
if str, ok := value.(string); ok {
fmt.Fprintf(w, "%q: %q", key, str)
} else {
fmt.Fprintf(w, "%q: %v", key, value)
}
}
fmt.Fprintf(w, "{\n")
expvar.Do(func(kv expvar.KeyValue) {
report(kv.Key, kv.Value)
})
fmt.Fprintf(w, "\n}\n")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/debug/vars", metricsHandler)
endpoint := http.ListenAndServe("localhost:6060", mux)
}
默认注册的访问路径是/debug/vars, 编译启动之后,就可以通过 http://localhost:6060/debug/vars 来访问 expvar 以 JSON 格式暴露出来的这些内部变量,默认提供了 Golang 的 runtime.Memstats 信息,也就是上面分析的数据源,当然你还可以注册自己的变量,这里暂时不提。
OK,现在我们的 Golang 程序已经启动了,并且通过 expvar 暴露出了运行时的内存使用情况,现在我们需要使用 Metricbeat 来获取这些信息并存进 Elasticsearch。
关于 Metricbeat 的安装其实很简单,下载对应平台的包解压(下载地址:https://www.elastic.co/downloads/beats/metricbeat ),启动 Metricbeat 前,修改配置文件:metricbeat.ymlmetricbeat.modules:
- module: golang
metricsets: ["heap"]
enabled: true
period: 10s
hosts: ["localhost:6060"]
heap.path: "/debug/vars"
上面的参数启用了 Golang 监控模块,并且会10秒获取一次配置路径的返回内存数据,我们同样配置该配置文件,设置数据输出到本机的 Elasticsearch:output.elasticsearch:
hosts: ["localhost:9200"]
现在启动 Metricbeat:./metricbeat -e -v
现在在 Elasticsearch 应该就有数据了,当然记得确保 Elasticsearch 和 Kibana 是可用状态,你可以在 Kibana 根据数据灵活自定义可视化,推荐使用 Timelion 来进行分析,当然为了方便也可以直接导入提供的样例仪表板,就是上面第一个图的效果。
关于如何导入样例仪表板请参照这个文档:https://www.elastic.co/guide/e ... .html
除了监控已经有的内存信息之外,如果你还有一些内部的业务指标想要暴露出来,也是可以的,通过 expvar 来做同样可以。一个简单的例子如下:var inerInt int64 = 1024
pubInt := expvar.NewInt("your_metric_key")
pubInt.Set(inerInt)
pubInt.Add(2)
在 Metricbeat 内部也同样暴露了很多内部运行的信息,所以 Metricbeat 可以自己监控自己了。。。
首先,启动的时候带上参数设置pprof监控的地址,如下:./metricbeat -httpprof="127.0.0.1:6060" -e -v
这样我们就能够通过 [url=http://127.0.0.1:6060/debug/vars]http://127.0.0.1:6060/debug/vars[/url] 访问到内部运行情况了,如下:{
"output.events.acked": 1088,
"output.write.bytes": 1027455,
"output.write.errors": 0,
"output.messages.dropped": 0,
"output.elasticsearch.publishEvents.call.count": 24,
"output.elasticsearch.read.bytes": 12215,
"output.elasticsearch.read.errors": 0,
"output.elasticsearch.write.bytes": 1027455,
"output.elasticsearch.write.errors": 0,
"output.elasticsearch.events.acked": 1088,
"output.elasticsearch.events.not_acked": 0,
"output.kafka.events.acked": 0,
"output.kafka.events.not_acked": 0,
"output.kafka.publishEvents.call.count": 0,
"output.logstash.write.errors": 0,
"output.logstash.write.bytes": 0,
"output.logstash.events.acked": 0,
"output.logstash.events.not_acked": 0,
"output.logstash.publishEvents.call.count": 0,
"output.logstash.read.bytes": 0,
"output.logstash.read.errors": 0,
"output.redis.events.acked": 0,
"output.redis.events.not_acked": 0,
"output.redis.read.bytes": 0,
"output.redis.read.errors": 0,
"output.redis.write.bytes": 0,
"output.redis.write.errors": 0,
"beat.memstats.memory_total": 155721720,
"beat.memstats.memory_alloc": 3632728,
"beat.memstats.gc_next": 6052800,
"cmdline": ["./metricbeat","-httpprof=127.0.0.1:6060","-e","-v"],
"fetches": {"system-cpu": {"events": 4, "failures": 0, "success": 4}, "system-filesystem": {"events": 20, "failures": 0, "success": 4}, "system-fsstat": {"events": 4, "failures": 0, "success": 4}, "system-load": {"events": 4, "failures": 0, "success": 4}, "system-memory": {"events": 4, "failures": 0, "success": 4}, "system-network": {"events": 44, "failures": 0, "success": 4}, "system-process": {"events": 1008, "failures": 0, "success": 4}},
"libbeat.config.module.running": 0,
"libbeat.config.module.starts": 0,
"libbeat.config.module.stops": 0,
"libbeat.config.reloads": 0,
"memstats": {"Alloc":3637704,"TotalAlloc":155
... ...
比如,上面就能看到output模块Elasticsearch的处理情况,如 output.elasticsearch.events.acked 参数表示发送到 Elasticsearch Ack返回之后的消息。
现在我们要修改 Metricbeat 的配置文件,Golang 模块有两个 metricset,可以理解为两个监控的指标类型,我们现在需要加入一个新的 expvar 类型,这个即自定义的其他指标,相应配置文件修改如下:- module: golang
metricsets: ["heap","expvar"]
enabled: true
period: 1s
hosts: ["localhost:6060"]
heap.path: "/debug/vars"
expvar:
namespace: "metricbeat"
path: "/debug/vars"
上面的一个参数 namespace 表示自定义指标的一个命令空间,主要是为了方便管理,这里是 Metricbeat 自身的信息,所以 namespace 就是 metricbeat。
重启 Metricbeat 应该就能收到新的数据了,我们前往 Kibana。
这里假设关注 output.elasticsearch.events.acked和
output.elasticsearch.events.not_acked这两个指标,我们在Kibana里面简单定义一个曲线图就能看到 Metricbeat 发往 Elasticsearch 消息的成功和失败趋势。
Timelion 表达式:.es("metricbeat*",metric="max:golang.metricbeat.output.elasticsearch.events.acked").derivative().label("Elasticsearch Success"),.es("metricbeat*",metric="max:golang.metricbeat.output.elasticsearch.events.not_acked").derivative().label("Elasticsearch Failed")
效果如下:
从上图可以看到,发往 Elasticsearch 的消息很稳定,没有出现丢消息的情况,同时关于 Metricbeat 的内存情况,我们打开导入的 Dashboard 查看:
关于如何使用 Metricbeat 来监控 Golang 应用程序的内容基本上就差不多到这里了,上面介绍了如何基于 expvar 来监控 Golang 的内存情况和自定义业务监控指标,在结合 Elastic Stack 可以快速的进行分析,希望对大家有用。
最后,这个 Golang 模块目前还没 release,估计在 beats 6.0 发布,有兴趣尝鲜的可以自己下载源码打包。 对话 Kibana 之父:如果需要,你应该自己动手编写工具
资讯动态 • medcl 发表了文章 • 2 个评论 • 8499 次浏览 • 2017-01-11 11:45
如果你有一个想法,把它code出来,build起来。不要等其他人的开源代码,有可能你会等到,但是有可能你永远等不到。在你写出来之后,你没准会收获惊喜。
kibana搜索10000条输入限制如何解除
回复Kibana • onionwithhoney 发起了问题 • 1 人关注 • 0 个回复 • 4966 次浏览 • 2023-01-05 15:02
怎么查看 Kibana dashboard中最终执行的query语句
回复Kibana • sdx 回复了问题 • 2 人关注 • 1 个回复 • 989 次浏览 • 2022-07-08 11:19
kibana7.14配置索引模式权限后页面依旧可以看到
回复Kibana • caster_QL 回复了问题 • 1 人关注 • 1 个回复 • 1504 次浏览 • 2021-09-30 18:26
kibana 7.14 本地开发模式提示crash
回复Kibana • tongchuan1992 回复了问题 • 2 人关注 • 1 个回复 • 1639 次浏览 • 2021-09-07 10:46
堆栈监测 监测beats bug有人遇到过吗
回复Kibana • tongchuan1992 回复了问题 • 2 人关注 • 1 个回复 • 1542 次浏览 • 2021-07-08 08:47
kibana如何才能使用nested的字段作为可视化的条件?
回复Kibana • liuxg 回复了问题 • 2 人关注 • 1 个回复 • 1524 次浏览 • 2021-07-02 10:01
kibana如何做出只查询出自己创建的索引的?
回复Elasticsearch • startjava 发起了问题 • 1 人关注 • 0 个回复 • 1556 次浏览 • 2021-07-01 16:04
在kibana中使用markdown动态展示多个指标的比率
回复Kibana • cclibra 发起了问题 • 1 人关注 • 0 个回复 • 2083 次浏览 • 2020-11-19 11:14
kibana想要用ldap登入认证是不是就要买x-pack?
回复Kibana • Gaolin Cheng 回复了问题 • 3 人关注 • 4 个回复 • 4993 次浏览 • 2020-11-06 17:04
ES7.3版本设置kibana用户名和密码,无法登陆,求解!
回复Kibana • Florence 回复了问题 • 5 人关注 • 5 个回复 • 9661 次浏览 • 2020-09-23 08:56
Web Scraper + Elasticsearch + Kibana + SearchKit 打造的豆瓣电影top250 搜索演示系统
Elasticsearch • 森 发表了文章 • 0 个评论 • 4517 次浏览 • 2023-04-09 10:56
Web Scraper + Elasticsearch + Kibana + SearchKit 打造的豆瓣电影top250 搜索演示系统
作者:小森同学
声明:电影数据来源于“豆瓣电影”,如有侵权,请联系删除
Web Scraper
{
"_id": "top250",
"startUrl": ["https://movie.douban.com/top250?start=[0-225:25]&filter="],
"selectors": [{
"id": "container",
"multiple": true,
"parentSelectors": ["_root"],
"selector": ".grid_view li",
"type": "SelectorElement"
}, {
"id": "name",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "span.title:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "number",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "em",
"type": "SelectorText"
}, {
"id": "score",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "span.rating_num",
"type": "SelectorText"
}, {
"id": "review",
"multiple": false,
"parentSelectors": ["container"],
"regex": "",
"selector": "span.inq",
"type": "SelectorText"
}, {
"id": "year",
"multiple": false,
"parentSelectors": ["container"],
"regex": "\\d{4}",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "tour_guide",
"multiple": false,
"parentSelectors": ["container"],
"regex": "^导演: \\S*",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "type",
"multiple": false,
"parentSelectors": ["container"],
"regex": "[^/]+$",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "area",
"multiple": false,
"parentSelectors": ["container"],
"regex": "[^\\/]+(?=\\/[^\\/]*$)",
"selector": "p:nth-of-type(1)",
"type": "SelectorText"
}, {
"id": "detail_link",
"multiple": false,
"parentSelectors": ["container"],
"selector": ".hd a",
"type": "SelectorLink"
}, {
"id": "director",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "",
"selector": "span:nth-of-type(1) .attrs a",
"type": "SelectorText"
}, {
"id": "screenwriter",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=编剧: )[\\u4e00-\\u9fa5A-Za-z0-9/()\\·\\s]+(?=主演)",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "film_length",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "\\d+",
"selector": "span[property='v:runtime']",
"type": "SelectorText"
}, {
"id": "IMDb",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=[IMDb:\\s+])\\S*(?=\\d*$)",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "language",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=语言: )\\S+",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "alias",
"multiple": false,
"parentSelectors": ["detail_link"],
"regex": "(?<=又名: )[\\u4e00-\\u9fa5A-Za-z0-9/()\\s]+(?=IMDb)",
"selector": "div#info",
"type": "SelectorText"
}, {
"id": "pic",
"multiple": false,
"parentSelectors": ["container"],
"selector": "img",
"type": "SelectorImage"
}]
}
elasticsearch
{
"mappings": {
"properties": {
"IMDb": {
"type": "keyword",
"copy_to": [
"all"
]
},
"alias": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"all": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"area": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"director": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"film_length": {
"type": "long"
},
"id": {
"type": "keyword"
},
"language": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"link": {
"type": "keyword"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"number": {
"type": "long"
},
"photo": {
"type": "keyword"
},
"review": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"score": {
"type": "double"
},
"screenwriter": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"type": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"copy_to": [
"all"
],
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"year": {
"type": "long"
}
}
}
}
kibana
需要使用pipeline对索引字段进行处理,如对type 通过空格进行分割为数组等,可以参照官方文档或其他博客。
制作仪表板省略, 请自行搜索
SearchKit
在 Kibana 里统一访问来自不同集群的索引
资料分享 • medcl 发表了文章 • 0 个评论 • 1370 次浏览 • 2022-04-21 15:29
在 Kibana 里统一访问来自不同集群的索引
现在有这么一个需求,客户根据需要将数据按照业务维度划分,将索引分别存放在了不同的三个集群, 将一个大集群拆分成多个小集群有很多好处,比如降低了耦合,带来了集群可用性和稳定性方面的好处,也避免了单个业务的热点访问造成其他业务的影响, 尽管拆分集群是很常见的玩法,但是管理起来不是那么方便了,尤其是在查询的时候,可能要分别访问三套集群各自的 API,甚至要切换三套不同的 Kibana 来访问集群的数据, 那么有没有办法将他们无缝的联合在一起呢?
极限网关!
答案自然是有的,通过将 Kibana 访问 Elasticsearch 的地址切换为极限网关的地址,我们可以将请求按照索引来进行智能的路由, 也就是当访问不同的业务索引时会智能的路由到不同的集群,如下图:
上图,我们分别有 3 个不同的索引:
- apm-*
- erp-*
- mall-*
分别对应不同的三套 Elasticsearch 集群:
- ES1-APM
- ES2-ERP
- ES3-MALL
接下来我们来看如何在极限网关里面进行相应的配置来满足这个业务需求。
配置集群信息
首先配置 3 个集群的连接信息。
elasticsearch:
- name: es1-apm
enabled: true
endpoints:
- http://192.168.3.188:9206
- name: es2-erp
enabled: true
endpoints:
- http://192.168.3.188:9207
- name: es3-mall
enabled: true
endpoints:
- http://192.168.3.188:9208
配置服务 Flow
然后,我们定义 3 个 Flow,分别对应用来访问 3 个不同的 Elasticsearch 集群,如下:
flow:
- name: es1-flow
filter:
- elasticsearch:
elasticsearch: es1-apm
- name: es2-flow
filter:
- elasticsearch:
elasticsearch: es2-erp
- name: es3-flow
filter:
- elasticsearch:
elasticsearch: es3-mall
然后再定义一个 flow 用来进行路径的判断和转发,如下:
- name: default-flow
filter:
- switch:
remove_prefix: false
path_rules:
- prefix: apm-
flow: es1-flow
- prefix: erp-
flow: es2-flow
- prefix: mall-
flow: es3-flow
- flow: #default flow
flows:
- es1-flow
根据请求路径里面的索引前缀来匹配不同的索引,并转发到不同的 Flow。
配置路由信息
接下来,我们定义路由信息,具体配置如下:
router:
- name: my_router
default_flow: default-flow
指向上面定义的默认 flow 来统一请求的处理。
定义服务及关联路由
最后,我们定义一个监听为 8000 端口的服务,用来提供给 Kibana 来进行统一的入口访问,如下:
entry:
- name: es_entry
enabled: true
router: my_router
max_concurrency: 10000
network:
binding: 0.0.0.0:8000
完整配置
最后的完整配置如下:
path.data: data
path.logs: log
entry:
- name: es_entry
enabled: true
router: my_router
max_concurrency: 10000
network:
binding: 0.0.0.0:8000
flow:
- name: default-flow
filter:
- switch:
remove_prefix: false
path_rules:
- prefix: apm-
flow: es1-flow
- prefix: erp-
flow: es2-flow
- prefix: mall-
flow: es3-flow
- flow: #default flow
flows:
- es1-flow
- name: es1-flow
filter:
- elasticsearch:
elasticsearch: es1-apm
- name: es2-flow
filter:
- elasticsearch:
elasticsearch: es2-erp
- name: es3-flow
filter:
- elasticsearch:
elasticsearch: es3-mall
router:
- name: my_router
default_flow: default-flow
elasticsearch:
- name: es1-apm
enabled: true
endpoints:
- http://192.168.3.188:9206
- name: es2-erp
enabled: true
endpoints:
- http://192.168.3.188:9207
- name: es3-mall
enabled: true
endpoints:
- http://192.168.3.188:9208
启动网关
直接启动网关,如下:
➜ gateway git:(master) ✗ ./bin/gateway -config sample-configs/elasticsearch-route-by-index.yml
___ _ _____ __ __ __ _
/ _ \ /_\ /__ \/__\/ / /\ \ \/_\ /\_/\
/ /_\///_\\ / /\/_\ \ \/ \/ //_\\\_ _/
/ /_\\/ _ \/ / //__ \ /\ / _ \/ \
\____/\_/ \_/\/ \__/ \/ \/\_/ \_/\_/
[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2022-04-20 08:23:56, 2023-12-31 10:10:10, 51650a5c3d6aaa436f3c8a8828ea74894c3524b9
[04-21 13:41:21] [INF] [app.go:174] initializing gateway.
[04-21 13:41:21] [INF] [app.go:175] using config: /Users/medcl/go/src/infini.sh/gateway/sample-configs/elasticsearch-route-by-index.yml.
[04-21 13:41:21] [INF] [instance.go:72] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/c9bpg0ai4h931o4ngs3g
[04-21 13:41:21] [INF] [app.go:283] gateway is up and running now.
[04-21 13:41:21] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es1-apm] hosts: [] => [192.168.3.188:9206]
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es2-erp] hosts: [] => [192.168.3.188:9207]
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es3-mall] hosts: [] => [192.168.3.188:9208]
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es2-erp] is available
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es1-apm] is available
[04-21 13:41:21] [INF] [entry.go:312] entry [es_entry] listen at: http://0.0.0.0:8000
[04-21 13:41:21] [INF] [module.go:116] all modules are started
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es3-mall] is available
[04-21 13:41:55] [INF] [reverseproxy.go:255] elasticsearch [es1-apm] hosts: [] => [192.168.3.188:9206]
网关启动成功之后,就可以通过网关的 IP+8000 端口来访问目标 Elasticsearch 集群了。
测试访问
首先通过 API 来访问测试一下,如下:
➜ ~ curl http://localhost:8000/apm-2022/_search -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /apm-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 05:45:44 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 162
< X-elastic-product: Elasticsearch
< X-Backend-Cluster: es1-apm
< X-Backend-Server: 192.168.3.188:9206
< X-Filters: filters->elasticsearch
<
* Connection #0 to host localhost left intact
{"took":142,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}%
可以看到 apm-2022 指向了后端的 es1-apm
集群。
继续测试,erp 索引的访问,如下:
➜ ~ curl http://localhost:8000/erp-2022/_search -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /erp-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 06:24:46 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 161
< X-Backend-Cluster: es2-erp
< X-Backend-Server: 192.168.3.188:9207
< X-Filters: filters->switch->filters->elasticsearch->skipped
<
* Connection #0 to host localhost left intact
{"took":12,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}%
继续测试,mall 索引的访问,如下:
➜ ~ curl http://localhost:8000/mall-2022/_search -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /mall-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 06:25:08 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 134
< X-Backend-Cluster: es3-mall
< X-Backend-Server: 192.168.3.188:9208
< X-Filters: filters->switch->filters->elasticsearch->skipped
<
* Connection #0 to host localhost left intact
{"took":8,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}%
完美转发。
修改 Kibana 配置
修改 Kibana 的配置文件: kibana.yml
,替换 Elasticsearch 的地址为网关地址(http://192.168.3.200:8000
),如下:
elasticsearch.hosts: ["http://192.168.3.200:8000"]
重启 Kibana 让配置生效。
效果如下
可以看到,在一个 Kibana 的开发者工具里面,我们已经可以像操作一个集群一样来同时读写实际上来自三个不同集群的索引数据了。
展望
通过极限网关,我们还可以非常灵活的进行在线请求的流量编辑,动态组合不同集群的操作。
使用极限网关来代理 Kibana
Kibana • medcl 发表了文章 • 0 个评论 • 1567 次浏览 • 2022-02-15 20:29
entry:
- name: my_es_entry
enabled: true
router: my_router
max_concurrency: 10000
network:
binding: 0.0.0.0:8000
skip_occupied_port: true
tls:
enabled: true
flow:
- name: default_flow
filter:
- basic_auth:
valid_users:
medcl: passwd
- http:
schema: "http" #https or http
host: "192.168.3.98:5601"
router:
- name: my_router
default_flow: default_flow
修改里面的 ip 为你实际的 Kibana IP 地址,如需多个,使用 hosts 参数,详见文档手册:
https://极限网关.com/docs/references/filters/http/
启动网关,因为自动开启了 https,访问网关的服务地址:https://localhost:8000,如下:
输入配置的用户名密码,即可。
Elastic日报 第1307期 (2021-01-12)
Elastic日报 • kin122 发表了文章 • 0 个评论 • 935 次浏览 • 2022-01-12 10:13
Elastic日报 第1245期 (2021-11-10)
Elastic日报 • kin122 发表了文章 • 0 个评论 • 896 次浏览 • 2021-11-10 09:41
如何修改kibana的默认主页
Kibana • 点火三周 发表了文章 • 3 个评论 • 7558 次浏览 • 2019-01-18 15:34
在6.0版本以前,登录kibana之后,默认会路由到app/kibana
下的discover
应用。
在6.3版本以后,新增了一个home路径/app/kibana#/home?_g=h@44136fa
,访问根路径\
会直接跳到以上路径。
希望在kibana上做更多定制化开发的同学,或许会有需求在登录kibana之后能够跳转到自己的页面。
要完成以上需求,只需要在kibana的配置文件里面增加一行:
server.defaultRoute: /app/system_portal
以上例子,我让kibana登录之后直接跳到我自己的app插件system_portal
配置默认路由的文件, src/server/http/get_default_route.js
:
import _ from 'lodash';
export default _.once(function (kbnServer) {
const {
config
} = kbnServer;
// 根目录basePath加上defaultRoute
return `${config.get('server.basePath')}${config.get('server.defaultRoute')}`;
});
默认路由就是定义在server.defaultRoute中,默认值是app/kibana
,可查看src/server/config/schema.js
:
import Joi from 'joi';
import { constants as cryptoConstants } from 'crypto';
import os from 'os';
import { fromRoot } from '../../utils';
import { getData } from '../path';
export default async () => Joi.object({
pkg: Joi.object({
version: Joi.string().default(Joi.ref('$version')),
branch: Joi.string().default(Joi.ref('$branch')),
buildNum: Joi.number().default(Joi.ref('$buildNum')),
buildSha: Joi.string().default(Joi.ref('$buildSha')),
}).default(),
env: Joi.object({
name: Joi.string().default(Joi.ref('$env')),
dev: Joi.boolean().default(Joi.ref('$dev')),
prod: Joi.boolean().default(Joi.ref('$prod'))
}).default(),
dev: Joi.object({
basePathProxyTarget: Joi.number().default(5603),
}).default(),
pid: Joi.object({
file: Joi.string(),
exclusive: Joi.boolean().default(false)
}).default(),
cpu: Joi.object({
cgroup: Joi.object({
path: Joi.object({
override: Joi.string().default()
})
})
}),
cpuacct: Joi.object({
cgroup: Joi.object({
path: Joi.object({
override: Joi.string().default()
})
})
}),
server: Joi.object({
uuid: Joi.string().guid().default(),
name: Joi.string().default(os.hostname()),
host: Joi.string().hostname().default('localhost'),
port: Joi.number().default(5601),
maxPayloadBytes: Joi.number().default(1048576),
autoListen: Joi.boolean().default(true),
defaultRoute: Joi.string().default('/app/kibana').regex(/^\//, `start with a slash`),
basePath: Joi.string().default('').allow('').regex(/(^$|^\/.*[^\/]$)/, `start with a slash, don't end with one`),
rewriteBasePath: Joi.boolean().when('basePath', {
is: '',
then: Joi.default(false).valid(false),
otherwise: Joi.default(false),
}),
customResponseHeaders: Joi.object().unknown(true).default({}),
ssl: Joi.object({
enabled: Joi.boolean().default(false),
redirectHttpFromPort: Joi.number(),
certificate: Joi.string().when('enabled', {
is: true,
then: Joi.required(),
}),
key: Joi.string().when('enabled', {
is: true,
then: Joi.required()
}),
keyPassphrase: Joi.string(),
certificateAuthorities: Joi.array().single().items(Joi.string()).default(),
supportedProtocols: Joi.array().items(Joi.string().valid('TLSv1', 'TLSv1.1', 'TLSv1.2')),
cipherSuites: Joi.array().items(Joi.string()).default(cryptoConstants.defaultCoreCipherList.split(':'))
}).default(),
cors: Joi.when('$dev', {
is: true,
then: Joi.object().default({
origin: ['*://localhost:9876'] // karma test server
}),
otherwise: Joi.boolean().default(false)
}),
xsrf: Joi.object({
disableProtection: Joi.boolean().default(false),
whitelist: Joi.array().items(
Joi.string().regex(/^\//, 'start with a slash')
).default(),
token: Joi.string().optional().notes('Deprecated')
}).default(),
}).default(),
logging: Joi.object().keys({
silent: Joi.boolean().default(false),
quiet: Joi.boolean()
.when('silent', {
is: true,
then: Joi.default(true).valid(true),
otherwise: Joi.default(false)
}),
verbose: Joi.boolean()
.when('quiet', {
is: true,
then: Joi.valid(false).default(false),
otherwise: Joi.default(false)
}),
events: Joi.any().default({}),
dest: Joi.string().default('stdout'),
filter: Joi.any().default({}),
json: Joi.boolean()
.when('dest', {
is: 'stdout',
then: Joi.default(!process.stdout.isTTY),
otherwise: Joi.default(true)
}),
useUTC: Joi.boolean().default(true),
})
.default(),
ops: Joi.object({
interval: Joi.number().default(5000),
}).default(),
plugins: Joi.object({
paths: Joi.array().items(Joi.string()).default(),
scanDirs: Joi.array().items(Joi.string()).default(),
initialize: Joi.boolean().default(true)
}).default(),
path: Joi.object({
data: Joi.string().default(getData())
}).default(),
optimize: Joi.object({
enabled: Joi.boolean().default(true),
bundleFilter: Joi.string().default('!tests'),
bundleDir: Joi.string().default(fromRoot('optimize/bundles')),
viewCaching: Joi.boolean().default(Joi.ref('$prod')),
watch: Joi.boolean().default(false),
watchPort: Joi.number().default(5602),
watchHost: Joi.string().hostname().default('localhost'),
watchPrebuild: Joi.boolean().default(false),
watchProxyTimeout: Joi.number().default(5 * 60000),
useBundleCache: Joi.boolean().default(Joi.ref('$prod')),
unsafeCache: Joi.when('$prod', {
is: true,
then: Joi.boolean().valid(false),
otherwise: Joi
.alternatives()
.try(
Joi.boolean(),
Joi.string().regex(/^\/.+\/$/)
)
.default(true),
}),
sourceMaps: Joi.when('$prod', {
is: true,
then: Joi.boolean().valid(false),
otherwise: Joi
.alternatives()
.try(
Joi.string().required(),
Joi.boolean()
)
.default('#cheap-source-map'),
}),
profile: Joi.boolean().default(false)
}).default(),
status: Joi.object({
allowAnonymous: Joi.boolean().default(false)
}).default(),
map: Joi.object({
manifestServiceUrl: Joi.string().default(' https://catalogue.maps.elastic.co/v2/manifest'),
emsLandingPageUrl: Joi.string().default('https://maps.elastic.co/v2'),
includeElasticMapsService: Joi.boolean().default(true)
}).default(),
tilemap: Joi.object({
url: Joi.string(),
options: Joi.object({
attribution: Joi.string(),
minZoom: Joi.number().min(0, 'Must be 0 or higher').default(0),
maxZoom: Joi.number().default(10),
tileSize: Joi.number(),
subdomains: Joi.array().items(Joi.string()).single(),
errorTileUrl: Joi.string().uri(),
tms: Joi.boolean(),
reuseTiles: Joi.boolean(),
bounds: Joi.array().items(Joi.array().items(Joi.number()).min(2).required()).min(2)
}).default()
}).default(),
regionmap: Joi.object({
includeElasticMapsService: Joi.boolean().default(true),
layers: Joi.array().items(Joi.object({
url: Joi.string(),
format: Joi.object({
type: Joi.string().default('geojson')
}).default({
type: 'geojson'
}),
meta: Joi.object({
feature_collection_path: Joi.string().default('data')
}).default({
feature_collection_path: 'data'
}),
attribution: Joi.string(),
name: Joi.string(),
fields: Joi.array().items(Joi.object({
name: Joi.string(),
description: Joi.string()
}))
}))
}).default(),
i18n: Joi.object({
defaultLocale: Joi.string().default('en'),
}).default(),
// This is a configuration node that is specifically handled by the config system
// in the new platform, and that the current platform doesn't need to handle at all.
__newPlatform: Joi.any(),
}).default();
为何要通过Kibana展示promethues的数据以及如何去做
Kibana • 点火三周 发表了文章 • 1 个评论 • 7322 次浏览 • 2018-12-27 10:59
Elastic stack不停的迭代中狂奔。在最新的V6.5版本发布后,我们可以发现,其路线图已经越来越倾向于成为一个全栈的,全链路的,从下至上,从底层硬件资源数据一直到上层用户数据,从资源监控,到性能监控,直至安全审计的智能化运维系统了。这其中解决的一个痛点是:企业中存在各种各样的业务系统,每个系统又存在不同的数据源和存储数据的数据库;同时在运维管理层面上,又各种不同的监控系统(资源监控,性能监控,安全和审计)以及上层的可视化系统。这样,导致运维人员需要面对繁多的系统、入口和数据维度,在处理问题时,需要登录不同的平台,并且无法对数据进行有效的关联分析,因此,是迫切需要一个强大的平台,能够快速便捷的处理这些问题的。 我们可以看到,从不停发布的beats,以及beats里面不停添加的modules:
以及支持的各种数据指标模版:
elastic stack在加速将越来越多的数据需要汇聚到一起,并且提供一个统一的接口进入,这就是Kibana。这里,我不打算深入的比较Kibana和Grafana,简单说一句,就是grafana的主要场景只是dashboard,并不适合将其用作一个将所有数据集中到一起,需要做各种维度的查询,分析,安全检查等功能的portal。所以,这里我们讨论的是Kibana上如何展示其他数据源的数据。
为什么是prometheus而不是beats
在这个人人上云的时代,无论是open stack还是K8S,最流行的资源监控软件我看到的是prometheus,特别是以node_exporter为基础的一系列metric采集工具,为prometheus提供了各种维度的监控数据。而对应的,elastic stack也提供了类似filebeat, metricbeat, packatbeat等一系列工具和对应的数据template。
我没有深入使用过prometheus,但作为一个beats的资深用户,我还是感觉到beats还存在诸多的问题,特别是filebeat上幽灵般存在的内存占用过多的问题,导致大规模在所有的节点上安装beats成为一种风险。并且,最主要的一个点,我觉得是beats采集的数据,是依赖于整个elastic stack进行展示的,而作为云的运维人员,其关心的重点是每个虚拟机,容器的资源监控情况,metric和alart是其重心,而非query,search,security等功能。并且安装一个prometheus,比安装整个elastic stack简便得多,消耗的资源也小的多。所以,普遍的,从主机运维人员的角度,肯定首选安装prometheus的exporter来作资源的监控,而非安装beats。
为什么Kibana上需要集成prometheus的数据
正因为之前所讲的,我们试图使用elastic stack作为一个多维度的统一的数据入口和展示工具,要求我们必须能在Kibana看到硬件资源监控级别的指标,而elastic stack提供的beats等工具,却并不为云运维人员所待见(因为他们更喜欢prometheus,而非elastic stack,原因见以上)。因此,如果我们需要将elastic stack打造为一套全栈的智能运维系统,大多数情况下,prometheus成为必须跨越的一个槛。
将prometheus上的数据转移到elasticsearch
这是我想到的第一个解决方案。可惜logstash上没有prometheus的input plugins。所以,我们还是需要beats。注意,在metricbeat上有一个prometheus的module,号称可以 fetch metric from prometheus exporter,但实际上只是一个乌龙,这个module的并不能从成千上万的云主机或者容器中拉取数据,它能做的只是获取prometheus服务器节点prometheus这个进程的基本数据,然并卵。 这里给大家介绍的是两个社区提供prometheus相关的beats:
但建议大家还是自己写一个beat吧,代码可以参考prombeat。 不过如果你仔细观看prometheus里面的数据,都是num type的,将其转存到elasticsearch绝对不是一个经济的选择:
将grafana集成到kibana中
这是为什么我在一开始提到了grafana,虽然它不适合做portal,但是极其适合做dashboard,而kibana又是如此的开放,随便做个插件,可以轻松的跳转到grafana的dashboard上。而grafana与prometheus又是如此的登对,看看grafana上的各种专业而美丽的prometheus的dashboard吧:
我们要做的是做一个kibana的插件,然后将关键参数传递给grafana,并跳转:
虽然kibana和grafana是两个不同的工具,但并不妨碍我们将它们放在一起工作。而Kibana的开放性和基于插件的独立开发模式,让我们可以更方便的将各种好用的开源工具集成到一起,这里展示的Kibana与grafana和promethues的集成,希望能给到你一些微光。
Kibana优化过程(Optimize)过长或无法结束的解决方案
Kibana • 点火三周 发表了文章 • 5 个评论 • 4712 次浏览 • 2018-12-12 11:06
使用过Kibana的同学应该都知道,当我们在kibana的配置文件中打开或者关闭功能,或者安装、卸载额外的插件后,重启kibana会触发一个优化的过程(optimize),如下图:
这个过程或长或短,视你电脑的性能而定。这里简单介绍一下该过程所要完成的事情。
Kibana是一个单页Web应用
首先,Kibana是一个单页的web应用。何为单页web应用?即所有的页面的读取都是在浏览器上完成,而与后台服务器无关。与后台服务器的通信只关乎数据,而非页面。所以,应用上所有的UI都被打包在一起,一次性的发送到了浏览器端,而不是通过URL到后台进行获取。所以,我们看到kibana的首页是下面这样的:
http://localhost:5601/app/kibana#/
注意这里的#
后,代表#
后面的内容会被浏览器提取,不往服务器端进行url的情况,而是在浏览器上进行内部重新渲染。因为所有的页面都是存储在浏览器的,所有在初次访问的时候,会加载大量的代码到浏览器端,这些代码都是被压缩过的bundle文件:
而optimize的过程,就是把这些原本可读性的源代码压缩为bundle.js的过程。因此,每当你对Kibana进行裁剪之后重启,因为前端的部分是完全由浏览器负责的,所有bundle文件需要重新生成后再发给浏览器,所以会触发optimize的过程。
Kibana在6.2.0版本之后,常规版本已经默认自带了xpack(当然,你还是可以直接下载不带xpack的开源社区版),导致Kibana的size已经到了200M左右,而且越往后的版本,功能越多,代码量越大,每次optimize的过程都会耗费更多的时间。一般来说,我们会将Kibana部署在单独的机器上,因为这仅仅是一个web后端,通常我们不会分配比较优质的资源,(2C4G都算浪费的了),这种情况下面,每次我们裁剪后重启Kibana都会耗费半个小时~1个小时的时间,更有甚者直接hang住,查看系统日志才知道OOM了。
Nodejs的内存机制
Kibana是用Nodejs编写的程序,在一般的后端语言中,基本的内存使用上基本没有什么限制,但是在nodeJs中却只能使用部分内存。在64位系统下位约为1.4G,在32位系统下约为0.7G,造成这个问题的主要原因是因为nodeJs基于V8构建,V8使用自己的方式来管理和分配内存,这一套管理方式在浏览器端使用绰绰有余,但是在nodeJs中这却限制了开发者,在应用中如果碰到了这个限制,就会造成进程退出。
Nodejs内存机制对Kibana优化的影响
因为Kibana的代码体量越来越大,将所有的代码加载到内存之后,再解析语法树,进行bundle的转换所耗费的内存已经接近1.4G的限制了,当你安装更多插件,比如sentinl的时候,系统往往已经无法为继,导致Kibana无法启动
解决方案
这种情况下,我们需要在Kibana启动的时候,指定NodeJs使用更多的内存。这个可以通过设置Node的环境变量办到。
NODE_OPTIONS="--max-old-space-size=4096"
当然,我的建议是直接指定在kibana的启动脚本当中,修改/usr/share/kibana/bin/kibana
文件为:
#!/bin/sh
SCRIPT=$0
# SCRIPT may be an arbitrarily deep series of symlinks. Loop until we have the concrete path.
while [ -h "$SCRIPT" ] ; do
ls=$(ls -ld "$SCRIPT")
# Drop everything prior to ->
link=$(expr "$ls" : '.*-> \(.*\)$')
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=$(dirname "$SCRIPT")/"$link"
fi
done
DIR="$(dirname "${SCRIPT}")/.."
NODE="${DIR}/node/bin/node"
test -x "$NODE" || NODE=$(which node)
if [ ! -x "$NODE" ]; then
echo "unable to find usable node.js executable."
exit 1
fi
NODE_ENV=production exec "${NODE}" $NODE_OPTIONS --max_old_space_size=3072 --no-warnings "${DIR}/src/cli" ${@}
改动在最后一句:NODE_ENV=production exec "${NODE}" $NODE_OPTIONS --max_old_space_size=3072 --no-warnings "${DIR}/src/cli" ${@}
这样,我们可以保证Kibana能顺利的完成optimize的过程
Day 3 - kibana二次开发tips
Advent • vvv 发表了文章 • 2 个评论 • 11564 次浏览 • 2018-12-03 09:11
介绍
大家好,我是vvv,这个名字和王者荣耀AG超玩会中的vv没有一毛钱关系,随意取的一个的名字,后来发现貌似不能改了。做过一些数据产品,正是这段时间里开始接触elasticstack,对kibana做过一些二次开发。今天主要想写一些开发过程中的一些tips,希望可以给大家带来一些帮助。
技术栈分析
既然我们的主题是kibana,我们先来看下kibana的主要技术栈。很早开始kibana就开始基于nodejs (hapi框架) + angular(1.x)来进行开发,后来引入了react。kibana本身的代码也经过了多次重构剥离。现在的kibana的代码结构更加清晰
前提
elasticstack发展迅速,现在已经是6.5版本了。我们今天要介绍的是6.x系列的版本,6.x各个版本会有一些细微差异,但大致一样
tips
官方提供kibana下载版本主要是编译后的release版本。如果要基于kibana做二次开发,我们需要去https://github.com/elastic/kibana 上面下载对应的分支。官方有相应的文档去说明如何安装开发环境。我这里有一些tips:
设置国内yarn源
yarn config --global set 'registry https://registry.npm.taobao.org'
一些耗时需要编译的包可以全局安装
yarn global add node-sass
多环境nodejs版本
不同kibana版本对nodejs版本要求也不一样,为了减少坑我们通常和官方要求的保持一致,如果你的电脑上需要运行多套不同版本的nodejs,那么你可能需要zsh + nvs, 会根据根目录的.node-version版本自动切换当前使用的node版本
IDE推荐
推荐使用vscode,轻量免费,支持很多插件。可以安装个prettier插件,帮助对代码做更好的格式化
debug
如果你用的不是上面我推荐的vscode的话,请忽略这一条。对于使用vscode的同学,首先在vsocde的设置里面开启:
"autoAttach": "on"
然后在vsocode里面打开一个终端,输入:
node --inspect-brk scripts/kibana.js --dev --oss --no-base-path
这个时候vscode就会在启动kibana dev模式的同时attach一个进程进去用于断点调试,对于调试node层非常方便。也能帮助你更好的阅读kibana源码
本地es
我们知道kibana是长在es之上,想要运行kibana怎么少得了es。kibana又一些命令命令可以快速的启动一个es环境:
下载并启动一个当前kibana需要的es版本
yarn es snapshot
灌入一些测试数据(如果需要定制灌入的数据可以看下这个脚本的帮助内容,加-h参数即可)
node scripts/makelogs
编译
kibana代码在release之前是要进行编译的。kibana提供了方便的命令行进行编译,甚至跨平台的交叉编译(生成不同平台的kibana release版本)。但是呢,有几个问题:
- kibana在编译的时候需要去aws上下载一些安装包,会导致正常情况下国内访问十分缓慢。(编译命令提供了几个参数可以关掉下载一些如nodejs等,但是还是很慢)
- build十分消耗cpu/gpu (mac的iterm2启动会做gpu优化)
解决办法:
- 如果你能解决网络问题,而且有性能不错的编译机器。这都不是问题
- 如果你对kibana的代码更改都是无侵入的(比如只是写了一些插件扩展),那么你可以去官方下载他们的snapshot版本
- 当然,如果你用的kibana版本就是release版本并且你的扩展都是插件,那么你直接用官方的release版本就好了
库的选型
-
server端: nodejs具有十分丰富的生态,你可以找到很多nodejs相关的库。kibana本身的后端web框架是基于node的hapi的。hapi是一个沃尔玛团队维护的企业级框架,其本身也有很多扩展。当你需要对web框架做一些扩展的时候,可以优先想到去hapi官方看下
- ui端: kibana有一套漂亮的ui,其本身也是单独剥离成了一个库,方便引入使用。当然你也可以引入一些其他的前端库来满足你的具体业务需求。推荐尽量使用原生的eui和kibana源码里面的一些封装。这样让你的引入更少,更容易维护。
国际化
国际化是kibana很早就开始立的一个项。这块的进度也是越来越快。新版的kibana里面用@kbn/i18n这个package来统一javascript,html, nodejs做国际化的事情(具体大家可以看下这个package的readme)。国际化这块有一些建议:
- 扩展插件的时候养成国际化的习惯
- 默认的语系不建议再次设置成一个json文件。因为最新的@kbn/i18n会提供一个默认的文本,用于默认情况下展示。所以我们是没必要重复去维护一个默认的语言翻译json
- 假设你的默认语言是英文(和kibana一致),只有当你想要替换kibana默认翻译的时候,才去覆写en.json
- 当你对原生kibana有国际化这种需求的时候,建议独立出一个i18n翻译的插件去维护各个语言翻译相关的东西
- 目前kibana的国际化还未100%,如果你想知道目前哪些文本内容是支持国际化的。可以尝试如下脚本:
node scripts/extract_default_translations \
--path src/core_plugins/kibana \
--output /tmp
- 各个插件的之间的翻译文件独立,即使是相同的翻译内容。插件文本内容养成预留国际化的习惯
总结
上面列举了一些我平时的一些经验。时间篇幅有限,未能一一列举。希望可以帮到大家吧。也希望可以和大家多多交流
推荐kibana插件Cleaner 管理ES index TTL
Kibana • truman.p.du 发表了文章 • 0 个评论 • 3669 次浏览 • 2018-09-05 09:23
Cleaner
这是一个管理index TTL 插件,精美UI,高效运维管理elasticsearch index助手
https://github.com/TrumanDu/cleaner
screenshots
config
-
scheduleTime
server job schedule period,unit second ,default value is 60 second.
you can edit it. like:
cleaner.scheduleTime: 100
-
mergePattern
merge pattern,default value is
[^a-z]+$
.you can edit it. like:
cleaner.mergePattern: '[\d]{4}[-|\.|/][\d]{1,2}[-|\.|/][\d]{1,2}'
development
See the kibana contributing guide for instructions setting up your development environment. Once you have completed that, use the following npm tasks.
-
npm start
Start kibana and have it include this plugin
-
npm start -- --config kibana.yml
You can pass any argument that you would normally send to
bin/kibana
by putting them after--
when runningnpm start
-
npm run build
Build a distributable archive
-
npm run test:browser
Run the browser tests in a real web browser
-
npm run test:server
Run the server tests using mocha
For more information about any of these commands run npm run ${task} -- --help
.
Elastic日报 第357期 (2018-08-08)
Elastic日报 • elk123 发表了文章 • 0 个评论 • 1843 次浏览 • 2018-08-08 23:03
Kibana TSVB 注解的使用
Kibana • medcl 发表了文章 • 0 个评论 • 6299 次浏览 • 2018-07-05 09:38
昨天介绍了 Kibana 的里程碑插件,举了个用里程碑来展示数据的注解,写完之后,还是觉得这个例子有点不是太好,
第一,里程碑时间轴还是比较独立,和其他时序图形的时间轴对不上,所以看起来,很不好进行参考,虽然可以首先对时间过滤到出现异常的范围,然后再看里程碑图表的信息,不过,这个实在是体验太差了,用里程碑显示独立的里程信息应该是很好的,如果要做数据的注解,有没有更好的办法呢?
答案是有的,以上一个图形展示的 TSVB 来说,TSVB 本来就自带了数据注解的功能,今天我来给大家介绍一下怎么使用。
-
打开 TSVB 的编辑,转到 Annotations 选项卡
-
在 Index Patterns 里面设置你要引用的数据,然后设置一个时间字段,此处为
@timestamp
-
设置要显示的 Tag 字段,支持多个,用逗号分隔
- 设置显示的标签,支持模板,
{{字段名}}
最后的效果及设置的截图,如下所示:
是不是很简单。
昨天介绍了 Kibana 的里程碑插件,举了个用里程碑来展示数据的注解,写完之后,还是觉得这个例子有点不是太好,
第一,里程碑时间轴还是比较独立,和其他时序图形的时间轴对不上,所以看起来,很不好进行参考,虽然可以首先对时间过滤到出现异常的范围,然后再看里程碑图表的信息,不过,这个实在是体验太差了,用里程碑显示独立的里程信息应该是很好的,如果要做数据的注解,有没有更好的办法呢?
答案是有的,以上一个图形展示的 TSVB 来说,TSVB 本来就自带了数据注解的功能,今天我来给大家介绍一下怎么使用。
-
打开 TSVB 的编辑,转到 Annotations 选项卡
-
在 Index Patterns 里面设置你要引用的数据,然后设置一个时间字段,此处为
@timestamp
-
设置要显示的 Tag 字段,支持多个,用逗号分隔
- 设置显示的标签,支持模板,
{{字段名}}
最后的效果及设置的截图,如下所示:
是不是很简单。
Kibana 里程碑插件的使用
Kibana • medcl 发表了文章 • 7 个评论 • 5753 次浏览 • 2018-07-04 11:07
今天介绍一下 Kibana 的里程碑插件的使用,这个是一个相对还比较新的可视化插件,可以用来对具有时间上下文相关的数据,以里程碑的方式来展现这些数据点在时间轴上的关联性。
这样说可能比较抽象,举个荔枝,你在 Elasticsearch 里面存的是服务器日志信息,然后有一天,老板说网站很慢,帮忙重启一下,(老板听说重启可以解决问题,反正他说他的笔记本重启之后就老快了),这个是一个已知的维护动作,所以你默默的在后台记录了重启的时间和是谁叫你重启的(这里是老板),到了月底的时候,老板让你把这个月的服务器运行数据给他看,然后问你为什么某一个时间服务器请求都为0,你打开 Kibana,指着其中一个时间点说,诺,这里,你让我重启了服务器。
是的,你可以对数据进行注解,用来解释数据和异常,这个是一个很好的场景,另外,还可以关联持续集成工具,每次谁代码提交了,你把这个作为一个事件,存到 es 里面,然后用里程碑可视化显示,那么这个提交造成的服务运行指标的变化,比如性能提升和下降,就会非常直观的关联到这次代码提交,同理,软件版本的发布也是一个里程碑事件,也可以展示并关联起来。然后,在使用的时候,还可以根据时间定位到感兴趣的地方,查看该段时间都发生了哪些自定义的事件和日志,方便分析。做安全方面的分析也可以用来跟踪和做入侵事后复盘的注解。
是不是,很多地方都能使用这个插件呢。
插件地址:https://github.com/walterra/kibana-milestones-vis/
演示截图:
关于如何使用,其实在该项目的 README 里面已经比较详细了。
1.首先找到对应的 Kibana 插件的版本,如果没有可能需要手动编译插件,有的话,直接找到下载地址。 https://github.com/walterra/kibana-milestones-vis/releases
2.使用 Kibana 的插件安装命令下载安装
➜ kibana-6.2.4-darwin-x86_64 bin/kibana-plugin install https://github.com/walterra/kibana-milestones-vis/releases/download/v6.2.4/kibana-milestones-vis-6.2.4.zip
Found previous install attempt. Deleting...
Attempting to transfer from https://github.com/walterra/kibana-milestones-vis/releases/download/v6.2.4/kibana-milestones-vis-6.2.4.zip
Transferring 1353656 bytes....................
Transfer complete
Retrieving metadata from plugin archive
Extracting plugin archive
Extraction complete
Optimizing and caching browser bundles...
3.启动 Kibana,然后进入 Visualize 面板,应该就能找到这个新的 Milestone 类型的可视化组件了。
加两个维护日志
和日志关联分析
4.还有一个隐藏的秘籍,就是可以支持图片作为标注
用图片代替文字,是不是更直观,如果你的数据是电影相关的,你可以放一个电影海报替代,如果你的是历史人物相关的,比如,可以换成人物头像,地点等等。
好了,是不是很炫,快去自己试试吧。
【分享】想用ELK做日志分析的TX们可以参考啦~~~
Elasticsearch • hw_cloudsearch 发表了文章 • 1 个评论 • 2932 次浏览 • 2018-05-21 11:24
向大家推荐华为云的Elasticsearch,免去您的运维烦恼!欢迎使用~~
Elasticsearch • hw_cloudsearch 发表了文章 • 1 个评论 • 3970 次浏览 • 2018-05-16 15:34