mirror of https://github.com/jeecgboot/jeecg-boot
解决升级undertow后,性能监控tomcat信息tab项展示的问题
parent
e877929a42
commit
1d18a54b8a
|
@ -1,7 +1,10 @@
|
||||||
package org.jeecg.config.init;
|
package org.jeecg.config.init;
|
||||||
|
|
||||||
import io.undertow.server.DefaultByteBufferPool;
|
import io.undertow.server.DefaultByteBufferPool;
|
||||||
|
import io.undertow.server.handlers.BlockingHandler;
|
||||||
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
|
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
|
||||||
|
import org.jeecg.modules.monitor.actuator.undertow.CustomUndertowMetricsHandler;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
|
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
|
||||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -12,7 +15,14 @@ import org.springframework.context.annotation.Configuration;
|
||||||
* 解决启动提示: WARN io.undertow.websockets.jsr:68 - UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
|
* 解决启动提示: WARN io.undertow.websockets.jsr:68 - UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class UndertowConfiguration implements WebServerFactoryCustomizer<UndertowServletWebServerFactory>{
|
public class UndertowConfiguration implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义undertow监控指标工具类
|
||||||
|
* for [QQYUN-11902]tomcat 替换undertow 这里的功能还没修改
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private CustomUndertowMetricsHandler customUndertowMetricsHandler;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void customize(UndertowServletWebServerFactory factory) {
|
public void customize(UndertowServletWebServerFactory factory) {
|
||||||
|
@ -24,6 +34,9 @@ public class UndertowConfiguration implements WebServerFactoryCustomizer<Underto
|
||||||
webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 8192));
|
webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 8192));
|
||||||
|
|
||||||
deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
|
deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
|
||||||
|
|
||||||
|
// 添加自定义 监控 handler
|
||||||
|
deploymentInfo.addInitialHandlerChainWrapper(next -> new BlockingHandler(customUndertowMetricsHandler.wrap(next)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package org.jeecg.modules.monitor.actuator.undertow;
|
||||||
|
|
||||||
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
|
import io.undertow.server.HttpHandler;
|
||||||
|
import io.undertow.server.HttpServerExchange;
|
||||||
|
import io.undertow.server.session.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义undertow监控指标工具类
|
||||||
|
* for [QQYUN-11902]tomcat 替换undertow 这里的功能还没修改
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2025/4/8 19:06
|
||||||
|
*/
|
||||||
|
@Component("jeecgCustomUndertowMetricsHandler")
|
||||||
|
public class CustomUndertowMetricsHandler {
|
||||||
|
|
||||||
|
// 用于统计已创建的 session 数量
|
||||||
|
private final LongAdder sessionsCreated = new LongAdder();
|
||||||
|
|
||||||
|
// 用于统计已销毁的 session 数量
|
||||||
|
private final LongAdder sessionsExpired = new LongAdder();
|
||||||
|
|
||||||
|
// 当前活跃的 session 数量
|
||||||
|
private final AtomicInteger activeSessions = new AtomicInteger();
|
||||||
|
|
||||||
|
// 历史最大活跃 session 数
|
||||||
|
private final AtomicInteger maxActiveSessions = new AtomicInteger();
|
||||||
|
|
||||||
|
// Undertow 内存 session 管理器(用于创建与管理 session)
|
||||||
|
private final InMemorySessionManager sessionManager = new InMemorySessionManager("undertow-session-manager");
|
||||||
|
|
||||||
|
// 使用 Cookie 存储 session ID
|
||||||
|
private final SessionConfig sessionConfig = new SessionCookieConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param meterRegistry
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2025/4/8 19:07
|
||||||
|
*/
|
||||||
|
public CustomUndertowMetricsHandler(MeterRegistry meterRegistry) {
|
||||||
|
// 注册 Micrometer 指标
|
||||||
|
meterRegistry.gauge("undertow.sessions.created", sessionsCreated, LongAdder::longValue);
|
||||||
|
meterRegistry.gauge("undertow.sessions.expired", sessionsExpired, LongAdder::longValue);
|
||||||
|
meterRegistry.gauge("undertow.sessions.active.current", activeSessions, AtomicInteger::get);
|
||||||
|
meterRegistry.gauge("undertow.sessions.active.max", maxActiveSessions, AtomicInteger::get);
|
||||||
|
|
||||||
|
// 添加 session 生命周期监听器,统计 session 创建与销毁
|
||||||
|
sessionManager.registerSessionListener(new SessionListener() {
|
||||||
|
@Override
|
||||||
|
public void sessionCreated(Session session, HttpServerExchange exchange) {
|
||||||
|
sessionsCreated.increment();
|
||||||
|
int now = activeSessions.incrementAndGet();
|
||||||
|
maxActiveSessions.getAndUpdate(max -> Math.max(max, now));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionDestroyed(Session session, HttpServerExchange exchange, SessionDestroyedReason reason) {
|
||||||
|
sessionsExpired.increment();
|
||||||
|
activeSessions.decrementAndGet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装 Undertow 的 HttpHandler,实现 session 自动创建逻辑
|
||||||
|
* @param next
|
||||||
|
* @return
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2025/4/8 19:07
|
||||||
|
*/
|
||||||
|
public HttpHandler wrap(HttpHandler next) {
|
||||||
|
return exchange -> {
|
||||||
|
// 获取当前 session,如果不存在则创建
|
||||||
|
Session session = sessionManager.getSession(exchange, sessionConfig);
|
||||||
|
if (session == null) {
|
||||||
|
sessionManager.createSession(exchange, sessionConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行下一个 Handler
|
||||||
|
next.handleRequest(exchange);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
<a-tabs v-model:activeKey="activeKey" @change="tabChange">
|
<a-tabs v-model:activeKey="activeKey" @change="tabChange">
|
||||||
<a-tab-pane key="1" tab="服务器信息"></a-tab-pane>
|
<a-tab-pane key="1" tab="服务器信息"></a-tab-pane>
|
||||||
<a-tab-pane key="2" tab="JVM信息" force-render></a-tab-pane>
|
<a-tab-pane key="2" tab="JVM信息" force-render></a-tab-pane>
|
||||||
<a-tab-pane key="3" tab="Tomcat信息"></a-tab-pane>
|
<!-- <a-tab-pane key="3" tab="Tomcat信息"></a-tab-pane> -->
|
||||||
|
<a-tab-pane key="6" tab="Undertow信息"></a-tab-pane>
|
||||||
<a-tab-pane key="4" tab="磁盘监控">
|
<a-tab-pane key="4" tab="磁盘监控">
|
||||||
<DiskInfo v-if="activeKey == 4" style="height: 100%"></DiskInfo>
|
<DiskInfo v-if="activeKey == 4" style="height: 100%"></DiskInfo>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
|
|
@ -30,6 +30,11 @@ enum Api {
|
||||||
tomcatSessionsRejected = '/actuator/metrics/tomcat.sessions.rejected',
|
tomcatSessionsRejected = '/actuator/metrics/tomcat.sessions.rejected',
|
||||||
|
|
||||||
memoryInfo = '/sys/actuator/memory/info',
|
memoryInfo = '/sys/actuator/memory/info',
|
||||||
|
// undertow 监控
|
||||||
|
undertowSessionsCreated = '/actuator/metrics/undertow.sessions.created',
|
||||||
|
undertowSessionsExpired = '/actuator/metrics/undertow.sessions.expired',
|
||||||
|
undertowSessionsActiveCurrent = '/actuator/metrics/undertow.sessions.active.current',
|
||||||
|
undertowSessionsActiveMax = '/actuator/metrics/undertow.sessions.active.max',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -207,6 +212,34 @@ export const getTomcatSessionsRejected = () => {
|
||||||
return defHttp.get({ url: Api.tomcatSessionsRejected }, { isTransformResponse: false });
|
return defHttp.get({ url: Api.tomcatSessionsRejected }, { isTransformResponse: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*undertow 已创建 session 数
|
||||||
|
*/
|
||||||
|
export const getUndertowSessionsCreated = () => {
|
||||||
|
return defHttp.get({ url: Api.undertowSessionsCreated }, { isTransformResponse: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*undertow 已过期 session 数
|
||||||
|
*/
|
||||||
|
export const getUndertowSessionsExpired = () => {
|
||||||
|
return defHttp.get({ url: Api.undertowSessionsExpired }, { isTransformResponse: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*undertow 当前活跃 session 数
|
||||||
|
*/
|
||||||
|
export const getUndertowSessionsActiveCurrent = () => {
|
||||||
|
return defHttp.get({ url: Api.undertowSessionsActiveCurrent }, { isTransformResponse: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*undertow 活跃 session 数峰值
|
||||||
|
*/
|
||||||
|
export const getUndertowSessionsActiveMax = () => {
|
||||||
|
return defHttp.get({ url: Api.undertowSessionsActiveMax }, { isTransformResponse: false });
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内存信息
|
* 内存信息
|
||||||
*/
|
*/
|
||||||
|
@ -230,6 +263,9 @@ export const getMoreInfo = (infoType) => {
|
||||||
if (infoType == '5') {
|
if (infoType == '5') {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (infoType == '6') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTextInfo = (infoType) => {
|
export const getTextInfo = (infoType) => {
|
||||||
|
@ -293,6 +329,16 @@ export const getTextInfo = (infoType) => {
|
||||||
'memory.runtime.usage': { color: 'purple', text: 'JVM内存使用率', unit: '%', valueType: 'Number' },
|
'memory.runtime.usage': { color: 'purple', text: 'JVM内存使用率', unit: '%', valueType: 'Number' },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (infoType == '6') {
|
||||||
|
// undertow 监控
|
||||||
|
return {
|
||||||
|
'undertow.sessions.created': { color: 'green', text: 'undertow 已创建 session 数', unit: '个' },
|
||||||
|
'undertow.sessions.expired': { color: 'green', text: 'undertow 已过期 session 数', unit: '个' },
|
||||||
|
'undertow.sessions.active.current': { color: 'green', text: 'undertow 当前活跃 session 数', unit: '个' },
|
||||||
|
'undertow.sessions.active.max': { color: 'green', text: 'undertow 活跃 session 数峰值', unit: '个' },
|
||||||
|
'undertow.sessions.rejected': { color: 'green', text: '超过session 最大配置后,拒绝的 session 个数', unit: '个' },
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -334,4 +380,13 @@ export const getServerInfo = (infoType) => {
|
||||||
if (infoType == '5') {
|
if (infoType == '5') {
|
||||||
return Promise.all([getMemoryInfo()]);
|
return Promise.all([getMemoryInfo()]);
|
||||||
}
|
}
|
||||||
|
// undertow监控
|
||||||
|
if (infoType == '6') {
|
||||||
|
return Promise.all([
|
||||||
|
getUndertowSessionsActiveCurrent(),
|
||||||
|
getUndertowSessionsActiveMax(),
|
||||||
|
getUndertowSessionsCreated(),
|
||||||
|
getUndertowSessionsExpired(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue