* sentinel-transport-netty-http will also retry when port specified has been used * LogBase support variable arguments * Remove duplicated JVM properties overriding in SentinelConfig * Add VersionUtil to get version from jarmaster
@@ -58,6 +58,7 @@ | |||||
<maven.deploy.version>2.8.2</maven.deploy.version> | <maven.deploy.version>2.8.2</maven.deploy.version> | ||||
<maven.gpg.version>1.6</maven.gpg.version> | <maven.gpg.version>1.6</maven.gpg.version> | ||||
<maven.jacoco.version>0.8.1</maven.jacoco.version> | <maven.jacoco.version>0.8.1</maven.jacoco.version> | ||||
<maven.jar.version>3.1.0</maven.jar.version> | |||||
</properties> | </properties> | ||||
<modules> | <modules> | ||||
@@ -182,6 +183,15 @@ | |||||
</executions> | </executions> | ||||
</plugin> | </plugin> | ||||
</plugins> | </plugins> | ||||
<pluginManagement> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-jar-plugin</artifactId> | |||||
<version>${maven.jar.version}</version> | |||||
</plugin> | |||||
</plugins> | |||||
</pluginManagement> | |||||
</build> | </build> | ||||
<profiles> | <profiles> | ||||
@@ -24,5 +24,19 @@ | |||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-jar-plugin</artifactId> | |||||
<configuration> | |||||
<archive> | |||||
<manifestEntries> | |||||
<Implementation-Version>${project.version}</Implementation-Version> | |||||
</manifestEntries> | |||||
</archive> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
</project> | </project> |
@@ -20,6 +20,7 @@ import com.alibaba.csp.sentinel.node.DefaultNode; | |||||
import com.alibaba.csp.sentinel.node.EntranceNode; | import com.alibaba.csp.sentinel.node.EntranceNode; | ||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slots.system.SystemRule; | import com.alibaba.csp.sentinel.slots.system.SystemRule; | ||||
import com.alibaba.csp.sentinel.util.VersionUtil; | |||||
/** | /** | ||||
* @author qinan.qn | * @author qinan.qn | ||||
@@ -28,7 +29,7 @@ import com.alibaba.csp.sentinel.slots.system.SystemRule; | |||||
*/ | */ | ||||
public final class Constants { | public final class Constants { | ||||
public static final String SENTINEL_VERSION = "0.2.1"; | |||||
public static final String SENTINEL_VERSION = VersionUtil.getVersion("0.2.1"); | |||||
public final static int MAX_CONTEXT_NAME_SIZE = 2000; | public final static int MAX_CONTEXT_NAME_SIZE = 2000; | ||||
public final static int MAX_SLOT_CHAIN_SIZE = 6000; | public final static int MAX_SLOT_CHAIN_SIZE = 6000; | ||||
@@ -77,15 +77,6 @@ public class SentinelConfig { | |||||
for (Object key : fileProps.keySet()) { | for (Object key : fileProps.keySet()) { | ||||
SentinelConfig.setConfig((String)key, (String)fileProps.get(key)); | SentinelConfig.setConfig((String)key, (String)fileProps.get(key)); | ||||
try { | |||||
String systemValue = System.getProperty((String)key); | |||||
if (!StringUtil.isEmpty(systemValue)) { | |||||
SentinelConfig.setConfig((String)key, systemValue); | |||||
} | |||||
} catch (Exception e) { | |||||
RecordLog.info(e.getMessage(), e); | |||||
} | |||||
RecordLog.info(key + " value: " + SentinelConfig.getConfig((String)key)); | |||||
} | } | ||||
} | } | ||||
} catch (Throwable ioe) { | } catch (Throwable ioe) { | ||||
@@ -94,7 +85,13 @@ public class SentinelConfig { | |||||
// JVM parameter override file config. | // JVM parameter override file config. | ||||
for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) { | for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) { | ||||
SentinelConfig.setConfig(entry.getKey().toString(), entry.getValue().toString()); | |||||
String configKey = entry.getKey().toString(); | |||||
String configValue = entry.getValue().toString(); | |||||
String configValueOld = getConfig(configKey); | |||||
SentinelConfig.setConfig(configKey, configValue); | |||||
if (configValueOld != null) { | |||||
RecordLog.info("JVM parameter overrides {0}: {1} -> {2}", configKey, configValueOld, configValue); | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -32,18 +32,20 @@ public class CommandCenterLog extends LogBase { | |||||
logHandler = makeLogger(FILE_NAME, heliumRecordLog); | logHandler = makeLogger(FILE_NAME, heliumRecordLog); | ||||
} | } | ||||
public static void info(String msg) { | |||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.INFO, msg); | |||||
public static void info(String detail, Object... params) { | |||||
log(heliumRecordLog, logHandler, Level.INFO, detail, params); | |||||
} | |||||
public static void info(String detail, Throwable e) { | |||||
log(heliumRecordLog, logHandler, Level.INFO, detail, e); | |||||
} | } | ||||
public static void info(String msg, Throwable e) { | |||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.INFO, msg, e); | |||||
public static void warn(String detail, Object... params) { | |||||
log(heliumRecordLog, logHandler, Level.WARNING, detail, params); | |||||
} | } | ||||
public static void warn(String msg, Throwable e) { | |||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.WARNING, msg, e); | |||||
public static void warn(String detail, Throwable e) { | |||||
log(heliumRecordLog, logHandler, Level.WARNING, detail, e); | |||||
} | } | ||||
} | } |
@@ -61,6 +61,26 @@ public class LogBase { | |||||
} | } | ||||
return logDir; | return logDir; | ||||
} | } | ||||
protected static void log(Logger logger, Handler handler, Level level, String detail, Object... params) { | |||||
if (detail == null) { | |||||
return; | |||||
} | |||||
LoggerUtils.disableOtherHandlers(logger, handler); | |||||
if (params.length == 0) { | |||||
logger.log(level, detail); | |||||
} else { | |||||
logger.log(level, detail, params); | |||||
} | |||||
} | |||||
protected static void log(Logger logger, Handler handler, Level level, String detail, Throwable throwable) { | |||||
if (detail == null) { | |||||
return; | |||||
} | |||||
LoggerUtils.disableOtherHandlers(logger, handler); | |||||
logger.log(level, detail, throwable); | |||||
} | |||||
/** | /** | ||||
* Get log file base directory path, the returned path is guaranteed end with {@link File#separator} | * Get log file base directory path, the returned path is guaranteed end with {@link File#separator} | ||||
@@ -32,24 +32,20 @@ public class RecordLog extends LogBase { | |||||
static { | static { | ||||
logHandler = makeLogger(FILE_NAME, heliumRecordLog); | logHandler = makeLogger(FILE_NAME, heliumRecordLog); | ||||
} | } | ||||
public static void info(String detail) { | |||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.INFO, detail); | |||||
public static void info(String detail, Object... params) { | |||||
log(heliumRecordLog, logHandler, Level.INFO, detail, params); | |||||
} | } | ||||
public static void info(String detail, Throwable e) { | public static void info(String detail, Throwable e) { | ||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.INFO, detail, e); | |||||
log(heliumRecordLog, logHandler, Level.INFO, detail, e); | |||||
} | } | ||||
public static void warn(String detail) { | |||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.WARNING, detail); | |||||
public static void warn(String detail, Object... params) { | |||||
log(heliumRecordLog, logHandler, Level.WARNING, detail, params); | |||||
} | } | ||||
public static void warn(String detail, Throwable e) { | public static void warn(String detail, Throwable e) { | ||||
LoggerUtils.disableOtherHandlers(heliumRecordLog, logHandler); | |||||
heliumRecordLog.log(Level.WARNING, detail, e); | |||||
log(heliumRecordLog, logHandler, Level.WARNING, detail, e); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,36 @@ | |||||
/* | |||||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
package com.alibaba.csp.sentinel.util; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | |||||
/** | |||||
* Get Sentinel version from MANIFEST.MF | |||||
* | |||||
* @author jason | |||||
* @since 0.2.1 | |||||
*/ | |||||
public class VersionUtil { | |||||
public static String getVersion(String defaultVersion) { | |||||
try { | |||||
String version = VersionUtil.class.getPackage().getImplementationVersion(); | |||||
return version == null || version.length() == 0 ? defaultVersion : version; | |||||
} catch (Throwable e) { | |||||
RecordLog.warn("return default version, ignore exception", e); | |||||
return defaultVersion; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
package com.alibaba.csp.sentinel.util; | |||||
import org.junit.Assert; | |||||
import org.junit.Test; | |||||
public class VersionUtilTest { | |||||
@Test | |||||
public void versionTest() { | |||||
String version = VersionUtil.getVersion("1.0"); | |||||
/** | |||||
* manifest cannot be load before package | |||||
*/ | |||||
Assert.assertEquals("1.0", version); | |||||
} | |||||
} |
@@ -20,5 +20,10 @@ | |||||
<groupId>com.alibaba</groupId> | <groupId>com.alibaba</groupId> | ||||
<artifactId>fastjson</artifactId> | <artifactId>fastjson</artifactId> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>junit</groupId> | |||||
<artifactId>junit</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
</project> | </project> |
@@ -18,14 +18,17 @@ package com.alibaba.csp.sentinel.transport.command.netty; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Map.Entry; | import java.util.Map.Entry; | ||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import java.util.concurrent.TimeUnit; | |||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig; | |||||
import com.alibaba.csp.sentinel.command.CommandHandler; | import com.alibaba.csp.sentinel.command.CommandHandler; | ||||
import com.alibaba.csp.sentinel.log.CommandCenterLog; | import com.alibaba.csp.sentinel.log.CommandCenterLog; | ||||
import com.alibaba.csp.sentinel.log.RecordLog; | |||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | import com.alibaba.csp.sentinel.util.StringUtil; | ||||
import io.netty.bootstrap.ServerBootstrap; | import io.netty.bootstrap.ServerBootstrap; | ||||
import io.netty.channel.Channel; | import io.netty.channel.Channel; | ||||
import io.netty.channel.ChannelFuture; | |||||
import io.netty.channel.EventLoopGroup; | import io.netty.channel.EventLoopGroup; | ||||
import io.netty.channel.nio.NioEventLoopGroup; | import io.netty.channel.nio.NioEventLoopGroup; | ||||
import io.netty.channel.socket.nio.NioServerSocketChannel; | import io.netty.channel.socket.nio.NioServerSocketChannel; | ||||
@@ -33,6 +36,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
@SuppressWarnings("rawtypes") | |||||
public final class HttpServer { | public final class HttpServer { | ||||
private static final int DEFAULT_PORT = 8719; | private static final int DEFAULT_PORT = 8719; | ||||
@@ -60,13 +64,40 @@ public final class HttpServer { | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
throw new IllegalArgumentException("Illegal port: " + TransportConfig.getPort()); | throw new IllegalArgumentException("Illegal port: " + TransportConfig.getPort()); | ||||
} | } | ||||
channel = b.bind(port).sync().channel(); | |||||
int retryCount = 0; | |||||
ChannelFuture channelFuture = null; | |||||
// loop for an successful binding | |||||
while (true) { | |||||
int newPort = getNewPort(port, retryCount); | |||||
try { | |||||
channelFuture = b.bind(newPort).sync(); | |||||
TransportConfig.setRuntimePort(newPort); | |||||
break; | |||||
} catch (Exception e) { | |||||
TimeUnit.MILLISECONDS.sleep(30); | |||||
RecordLog.warn("netty server bind error, port={0}, retry={1}", newPort, retryCount); | |||||
retryCount ++; | |||||
} | |||||
} | |||||
channel = channelFuture.channel(); | |||||
channel.closeFuture().sync(); | channel.closeFuture().sync(); | ||||
} finally { | } finally { | ||||
workerGroup.shutdownGracefully(); | workerGroup.shutdownGracefully(); | ||||
bossGroup.shutdownGracefully(); | bossGroup.shutdownGracefully(); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* increase port number every 3 tries | |||||
* | |||||
* @param basePort | |||||
* @param retryCount | |||||
* @return | |||||
*/ | |||||
private int getNewPort(int basePort, int retryCount) { | |||||
return basePort + retryCount / 3; | |||||
} | |||||
public void close() { | public void close() { | ||||
channel.close(); | channel.close(); | ||||
@@ -52,6 +52,7 @@ public class SimpleHttpCommandCenter implements CommandCenter { | |||||
private static final int DEFAULT_SERVER_SO_TIMEOUT = 3000; | private static final int DEFAULT_SERVER_SO_TIMEOUT = 3000; | ||||
private static final int DEFAULT_PORT = 8719; | private static final int DEFAULT_PORT = 8719; | ||||
@SuppressWarnings("rawtypes") | |||||
private static final Map<String, CommandHandler> handlerMap = new HashMap<String, CommandHandler>(); | private static final Map<String, CommandHandler> handlerMap = new HashMap<String, CommandHandler>(); | ||||
private ExecutorService executor = Executors.newSingleThreadExecutor( | private ExecutorService executor = Executors.newSingleThreadExecutor( | ||||
@@ -61,6 +62,7 @@ public class SimpleHttpCommandCenter implements CommandCenter { | |||||
private ServerSocket socketReference; | private ServerSocket socketReference; | ||||
@Override | @Override | ||||
@SuppressWarnings("rawtypes") | |||||
public void beforeStart() throws Exception { | public void beforeStart() throws Exception { | ||||
// Register handlers | // Register handlers | ||||
Map<String, CommandHandler> handlers = CommandHandlerProvider.getInstance().namedHandlers(); | Map<String, CommandHandler> handlers = CommandHandlerProvider.getInstance().namedHandlers(); | ||||
@@ -94,54 +96,56 @@ public class SimpleHttpCommandCenter implements CommandCenter { | |||||
@Override | @Override | ||||
public void run() { | public void run() { | ||||
int repeat = 0; | |||||
int tmpPort = port; | |||||
boolean success = false; | boolean success = false; | ||||
while (true) { | |||||
ServerSocket serverSocket = null; | |||||
try { | |||||
serverSocket = new ServerSocket(tmpPort); | |||||
} catch (IOException ex) { | |||||
CommandCenterLog.info( | |||||
String.format("IO error occurs, port: %d, repeat times: %d", tmpPort, repeat), ex); | |||||
tmpPort = adjustPort(repeat); | |||||
try { | |||||
TimeUnit.SECONDS.sleep(5); | |||||
} catch (InterruptedException e1) { | |||||
break; | |||||
} | |||||
repeat++; | |||||
} | |||||
if (serverSocket != null) { | |||||
CommandCenterLog.info("[CommandCenter] Begin listening at port " + serverSocket.getLocalPort()); | |||||
socketReference = serverSocket; | |||||
executor.submit(new ServerThread(serverSocket)); | |||||
success = true; | |||||
break; | |||||
} | |||||
ServerSocket serverSocket = getServerSocketFromBasePort(port); | |||||
if (serverSocket != null) { | |||||
CommandCenterLog.info("[CommandCenter] Begin listening at port " + serverSocket.getLocalPort()); | |||||
socketReference = serverSocket; | |||||
executor.submit(new ServerThread(serverSocket)); | |||||
success = true; | |||||
port = serverSocket.getLocalPort(); | |||||
} | } | ||||
if (!success) { | if (!success) { | ||||
tmpPort = PORT_UNINITIALIZED; | |||||
port = PORT_UNINITIALIZED; | |||||
} | } | ||||
TransportConfig.setRuntimePort(tmpPort); | |||||
TransportConfig.setRuntimePort(port); | |||||
executor.shutdown(); | executor.shutdown(); | ||||
} | } | ||||
/** | |||||
* Adjust the port to settle down. | |||||
*/ | |||||
private int adjustPort(int repeat) { | |||||
int mod = repeat / 5; | |||||
return port + mod; | |||||
} | |||||
}; | }; | ||||
new Thread(serverInitTask).start(); | new Thread(serverInitTask).start(); | ||||
} | } | ||||
/** | |||||
* Get a server socket from an avaliable port from a base port.<br> | |||||
* Increasement on port number will happen when the port has already been | |||||
* used.<br> | |||||
* | |||||
* @param basePort | |||||
* @return | |||||
*/ | |||||
private static ServerSocket getServerSocketFromBasePort(int basePort) { | |||||
int tryCount = 0; | |||||
while (true) { | |||||
try { | |||||
ServerSocket server = new ServerSocket(basePort + tryCount / 3, 100); | |||||
server.setReuseAddress(true); | |||||
return server; | |||||
} catch (IOException e) { | |||||
tryCount ++; | |||||
try { | |||||
TimeUnit.MILLISECONDS.sleep(30); | |||||
} catch (InterruptedException e1) { | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
@Override | @Override | ||||
public void stop() throws Exception { | public void stop() throws Exception { | ||||
@@ -204,10 +208,12 @@ public class SimpleHttpCommandCenter implements CommandCenter { | |||||
} | } | ||||
} | } | ||||
@SuppressWarnings("rawtypes") | |||||
public static CommandHandler getHandler(String commandName) { | public static CommandHandler getHandler(String commandName) { | ||||
return handlerMap.get(commandName); | return handlerMap.get(commandName); | ||||
} | } | ||||
@SuppressWarnings("rawtypes") | |||||
public static void registerCommands(Map<String, CommandHandler> handlerMap) { | public static void registerCommands(Map<String, CommandHandler> handlerMap) { | ||||
if (handlerMap != null) { | if (handlerMap != null) { | ||||
for (Entry<String, CommandHandler> e : handlerMap.entrySet()) { | for (Entry<String, CommandHandler> e : handlerMap.entrySet()) { | ||||
@@ -216,6 +222,7 @@ public class SimpleHttpCommandCenter implements CommandCenter { | |||||
} | } | ||||
} | } | ||||
@SuppressWarnings("rawtypes") | |||||
public static void registerCommand(String commandName, CommandHandler handler) { | public static void registerCommand(String commandName, CommandHandler handler) { | ||||
if (StringUtil.isEmpty(commandName)) { | if (StringUtil.isEmpty(commandName)) { | ||||
return; | return; | ||||