From dace864853d03579253076084922ab60bc083ef3 Mon Sep 17 00:00:00 2001 From: CrazyAirhead Date: Thu, 18 Jun 2026 17:25:49 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20solon-server-feathttp=20=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=B8=8D=E5=8F=97=20slf4j=20=E6=8E=A7?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solon-server-feathttp/pom.xml | 6 + .../feathttp/integration/FeatHttpPlugin.java | 216 ++++++++++++------ 2 files changed, 149 insertions(+), 73 deletions(-) diff --git a/solon-projects/solon-server/solon-server-feathttp/pom.xml b/solon-projects/solon-server/solon-server-feathttp/pom.xml index d702ad3be5..76e5bef3b5 100644 --- a/solon-projects/solon-server/solon-server-feathttp/pom.xml +++ b/solon-projects/solon-server/solon-server-feathttp/pom.xml @@ -33,6 +33,12 @@ ${feat-core.version} + + org.slf4j + jul-to-slf4j + ${slf4j.version} + + org.noear solon-test diff --git a/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java b/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java index 26a9ba70c8..63f409fec6 100644 --- a/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java +++ b/solon-projects/solon-server/solon-server-feathttp/src/main/java/org/noear/solon/server/feathttp/integration/FeatHttpPlugin.java @@ -15,6 +15,10 @@ */ package org.noear.solon.server.feathttp.integration; +import java.util.Enumeration; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; import org.noear.solon.Solon; import org.noear.solon.Utils; import org.noear.solon.core.*; @@ -28,103 +32,169 @@ import org.noear.solon.server.prop.impl.HttpServerProps; import org.noear.solon.server.prop.impl.WebSocketServerProps; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.bridge.SLF4JBridgeHandler; /** * @author airhead */ public final class FeatHttpPlugin implements Plugin { - static final Logger log = LoggerFactory.getLogger(FeatHttpPlugin.class); - - private static Signal _signal; - private FeatHttpServerComb _server; - - public static Signal signal() { - return _signal; + static final Logger log = LoggerFactory.getLogger(FeatHttpPlugin.class); + + /** feat-core 中使用 LoggerFactory.getLogger() 的所有类(基于 feat-core 2.1.0)。 升级 feat-core 版本时需同步检查此清单。 */ + private static final String[] FEAT_LOGGER_CLASSES = { + "tech.smartboot.feat.core.client.HttpRestImpl", + "tech.smartboot.feat.core.client.WebSocketClient", + "tech.smartboot.feat.core.common.FeatUtils", + "tech.smartboot.feat.core.server.handler.HttpStaticResourceHandler", + "tech.smartboot.feat.core.server.impl.Endpoint", + "tech.smartboot.feat.core.server.impl.HttpEndpoint", + "tech.smartboot.feat.core.server.impl.HttpMessageProcessor", + "tech.smartboot.feat.core.server.impl.HttpRequestProtocol", + "tech.smartboot.feat.core.server.upgrade.http2.Http2Session", + "tech.smartboot.feat.core.server.upgrade.websocket.WebSocketResponseImpl", + "tech.smartboot.feat.core.server.upgrade.websocket.WebSocketUpgrade", + "tech.smartboot.feat.router.Router", + "tech.smartboot.feat.router.session.LocalSessionManager", + }; + + private static Signal _signal; + private FeatHttpServerComb _server; + + public static Signal signal() { + return _signal; + } + + public static String solon_server_ver() { + return "FeatHttp 2.1/" + Solon.version(); + } + + @Override + public void start(AppContext context) throws Throwable { + if (context.app().enableHttp() == false) { + return; } - public static String solon_server_ver() { - return "FeatHttp 2.1/" + Solon.version(); + if (context.isStarted()) { + start0(context); + } else { + context.lifecycle( + ServerConstants.SIGNAL_LIFECYCLE_INDEX, + new LifecycleBean() { + @Override + public void postStart() throws Throwable { + start0(context); + } + }); } + } - @Override - public void start(AppContext context) throws Throwable { - if (context.app().enableHttp() == false) { - return; - } + @Override + public void stop() throws Throwable { + if (_server != null) { + _server.stop(); + _server = null; - if (context.isStarted()) { - start0(context); - } else { - context.lifecycle(ServerConstants.SIGNAL_LIFECYCLE_INDEX, new LifecycleBean() { - @Override - public void postStart() throws Throwable { - start0(context); - } - }); - } + log.info("Server:main: feat: Has Stopped (" + solon_server_ver() + ")"); } + } - @Override - public void stop() throws Throwable { - if (_server != null) { - _server.stop(); - _server = null; - - log.info("Server:main: feat: Has Stopped (" + solon_server_ver() + ")"); - } - } + private void start0(AppContext context) throws Throwable { + installJulBridge(); - private void start0(AppContext context) throws Throwable { - //初始化属性 - ServerProps.init(); - MultipartUtil.init(); + // 初始化属性 + ServerProps.init(); + MultipartUtil.init(); - HttpServerProps props = new HttpServerProps(); - final String _host = props.getHost(); - final int _port = props.getPort(); - final String _name = props.getName(); + HttpServerProps props = new HttpServerProps(); + final String _host = props.getHost(); + final int _port = props.getPort(); + final String _name = props.getName(); - long time_start = System.currentTimeMillis(); + long time_start = System.currentTimeMillis(); + _server = new FeatHttpServerComb(props); + _server.enableWebSocket(context.app().enableWebSocket()); + _server.setCoreThreads(props.getCoreThreads()); - _server = new FeatHttpServerComb(props); - _server.enableWebSocket(context.app().enableWebSocket()); - _server.setCoreThreads(props.getCoreThreads()); + if (props.isIoBound()) { + // 如果是io密集型的,加二段线程池 + _server.setExecutor(props.newWorkExecutor("feat-")); + } - if (props.isIoBound()) { - //如果是io密集型的,加二段线程池 - _server.setExecutor(props.newWorkExecutor("feat-")); - } + _server.setHandler(context.app()::tryHandle); - _server.setHandler(context.app()::tryHandle); + // 尝试事件扩展 + EventBus.publish(_server); + _server.start(_host, _port); - //尝试事件扩展 - EventBus.publish(_server); - _server.start(_host, _port); + final String _wrapHost = props.getWrapHost(); + final int _wrapPort = props.getWrapPort(); + _signal = new SignalSim(_name, _wrapHost, _wrapPort, "http", SignalType.HTTP); + context.app().signalAdd(_signal); + long time_end = System.currentTimeMillis(); - final String _wrapHost = props.getWrapHost(); - final int _wrapPort = props.getWrapPort(); - _signal = new SignalSim(_name, _wrapHost, _wrapPort, "http", SignalType.HTTP); - context.app().signalAdd(_signal); + String connectorInfo = + "solon.connector:main: feat: Started ServerConnector@{HTTP/1.1,[http/1.1]"; + if (context.app().enableWebSocket()) { + // 有名字定义时,添加信号注册 + WebSocketServerProps wsProps = WebSocketServerProps.getInstance(); + if (Utils.isNotEmpty(wsProps.getName())) { + SignalSim wsSignal = + new SignalSim(wsProps.getName(), _wrapHost, _wrapPort, "ws", SignalType.WEBSOCKET); + context.app().signalAdd(wsSignal); + } - long time_end = System.currentTimeMillis(); + String wsServerUrl = props.buildWsServerUrl(_server.isSecure()); + log.info(connectorInfo + "[WebSocket]}{" + wsServerUrl + "}"); + } - String connectorInfo = "solon.connector:main: feat: Started ServerConnector@{HTTP/1.1,[http/1.1]"; - if (context.app().enableWebSocket()) { - //有名字定义时,添加信号注册 - WebSocketServerProps wsProps = WebSocketServerProps.getInstance(); - if (Utils.isNotEmpty(wsProps.getName())) { - SignalSim wsSignal = new SignalSim(wsProps.getName(), _wrapHost, _wrapPort, "ws", SignalType.WEBSOCKET); - context.app().signalAdd(wsSignal); - } + String httpServerUrl = props.buildHttpServerUrl(_server.isSecure()); + log.info(connectorInfo + "}{" + httpServerUrl + "}"); + log.info( + "Server:main: feat: Started (" + + solon_server_ver() + + ") @" + + (time_end - time_start) + + "ms"); + } + + /** 1.将 SLF4JBridgeHandler 安装到 JUL root logger,2.预热所有 feat-core logger 并桥接到 SLF4J */ + private void installJulBridge() { + System.setProperty("feat.log.level", "ALL"); + SLF4JBridgeHandler.removeHandlersForRootLogger(); + SLF4JBridgeHandler.install(); + + bridgeFeatLoggers(); + } + + /** 桥接 feat-core RunLogger 创建的 JUL logger:移除原有 handler,打开 parent 传播。 */ + private void bridgeFeatLoggers() { + // 预热 feat-core 所有使用 LoggerFactory 的 logger + for (String className : FEAT_LOGGER_CLASSES) { + tech.smartboot.feat.core.common.logging.LoggerFactory.getLogger(className); + } - String wsServerUrl = props.buildWsServerUrl(_server.isSecure()); - log.info(connectorInfo + "[WebSocket]}{" + wsServerUrl + "}"); + LogManager manager = LogManager.getLogManager(); + Enumeration names = manager.getLoggerNames(); + while (names.hasMoreElements()) { + String name = names.nextElement(); + if (name != null && name.startsWith("tech.smartboot.feat")) { + java.util.logging.Logger julLogger = manager.getLogger(name); + if (julLogger != null) { + Handler[] handlers = julLogger.getHandlers(); + if (handlers == null || handlers.length == 0) { + continue; + } + + for (Handler h : handlers) { + julLogger.removeHandler(h); + } + + julLogger.setUseParentHandlers(true); + julLogger.setLevel(Level.ALL); } - - String httpServerUrl = props.buildHttpServerUrl(_server.isSecure()); - log.info(connectorInfo + "}{" + httpServerUrl + "}"); - log.info("Server:main: feat: Started (" + solon_server_ver() + ") @" + (time_end - time_start) + "ms"); + } } -} \ No newline at end of file + } +} -- Gitee