最近,公司要求要做一个监控系统,除了要有数据监控统计外,还需要做服务资源的监控。我稍微跟公司运维沟通了下,公司有使用grafana+prometheus做监控。
prometheus是套服务监控系统,自带图表,但图表支持不是很丰富。grafana是个开源的数据可视化工具,有丰富的图片功能,还有警报功能等,刚好可以与prometheus搭配使用。
一开始打算采用直接调用prometheus的接口+第三方可视化插件进行可视化开发,但发现除了grafana外,没有其他有丰富图表支持的工具,但grafana是独立的一套可视化工具,要在自己的前端里用上可能并不方便。
后面想了下,前端有个神奇的标签,可以将第三方网页嵌入自己的页面展示,他就是<iframe>,在iframe的src中配置URL地址,即可引用第三方页面。
<iframe src="http//127.0.0.1:3000/d/JsX_vEwGk/dashboard?orgId=1m"></iframe>
在嵌入链接后,发现无法显示页面,后面查阅资料,发现是两个原因:
1、grafana需要登录(看运维默认设置是否需要登录)
2、grafana不允许嵌入
解决方案:在grafana的配置中允许匿名访问,允许嵌入。
grafana配置文件默认在/etc/grafana/grafana.ini
1、允许匿名访问(不需要登录)
[auth.anonymous]
# enable anonymous access
enabled = true
2、允许被嵌入
allow_embedding = true
但是,公司运维告诉我,grafana映射了外网,必须要设置登录访问!!!
这样的话,就没那么简单了!
想了一下,发现只能做个代理转发,在代理的过程验证登录后转发到grafana。
方案1:用nginx,配置认证代理。(运维觉得这样他不好管理,就让我自己在我的后端写一个认证代理转发,这个大家看公司要求吧,我这里不采用本方案)
方案2:java做代理,这里用的是 smiley-http-proxy-servlet。
Talk is cheap,show you my code!
前端代码:
<div role="tabpanel" class="tab-pane" id="server">
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="/grafana/d/JsX_vEwGk/dashboard?orgId=1m&kiosk" allowfullscreen></iframe>
</div>
</div>
这里用了bootstrap,所以加了一些其他样式,让iframe可以响应式显示。
application.yml
#配置grafana的代理转发和授权key,key是用于完成Grafana身份认证的,需要事先在Grafana上创建
proxy:
grafana:
servlet_url: /grafana/*
target_url: http://127.0.0.1:3000/grafana
key: xxxxxxx
授权key的话,让运维提供。
这里有个小技巧:grafana的原URL地址最好配置加多一个路径/grafana/,否则可能出现访问正常,但静态资源加载失败,因为静态资源加载的按当前路径下为父目录。
pom.xml
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.11</version>
</dependency>
ProxyServletConfiguration.java:
public class ProxyServletConfiguration {
/**
* 读取配置文件中路由设置
*/
@Value("${proxy.grafana.servlet_url}")
private String servlet_url;
/**
* 读取配置中代理目标地址
*/
@Value("${proxy.grafana.target_url}")
private String target_url;
@Bean
public Servlet createProxyServlet() {
/** 创建新的ProxyServlet */
return new GrafanaProxyServlet();
}
@Bean
public ServletRegistrationBean proxyServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(createProxyServlet(), servlet_url);
//设置网址以及参数
Map<String, String> params = ImmutableMap.of("targetUri", target_url, "log", "true");
registrationBean.setInitParameters(params);
return registrationBean;
}
}
GrafanaProxyServlet.java:
public class GrafanaProxyServlet extends ProxyServlet {
@Value("${proxy.grafana.key}")
private String key;
@Override
protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse, HttpRequest proxyRequest) throws IOException {
if (this.doLog) {
this.log("proxy " + servletRequest.getMethod() + " uri: " + servletRequest.getRequestURI() + " -- " + proxyRequest.getRequestLine().getUri());
}
Object userObj = servletRequest.getSession().getAttribute("user");
log.info("登录拦截器校验 userObj = {}", JsonUtil.getJson().toJson(userObj));
if(null == userObj){
return null;
}
proxyRequest.setHeader("Authorization", "Basic "+key);
HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
return response;
}
}
这里我还做了自己系统的登录拦截判断,再执行grafana的代理转发。
大功告成!!!