- Support customized log and configuration properties directorymaster
@@ -15,17 +15,13 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.config; | package com.alibaba.csp.sentinel.config; | ||||
import com.alibaba.csp.sentinel.log.LogBase; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import com.alibaba.csp.sentinel.util.AppNameUtil; | import com.alibaba.csp.sentinel.util.AppNameUtil; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Properties; | import java.util.Properties; | ||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import java.util.concurrent.CopyOnWriteArraySet; | |||||
/** | /** | ||||
* The universal local config center of Sentinel. The config is retrieved from command line arguments | * The universal local config center of Sentinel. The config is retrieved from command line arguments | ||||
@@ -64,7 +60,6 @@ public class SentinelConfig { | |||||
try { | try { | ||||
initialize(); | initialize(); | ||||
loadProps(); | loadProps(); | ||||
resolveAppType(); | resolveAppType(); | ||||
RecordLog.info("[SentinelConfig] Application type resolved: " + appType); | RecordLog.info("[SentinelConfig] Application type resolved: " + appType); | ||||
} catch (Throwable ex) { | } catch (Throwable ex) { | ||||
@@ -91,49 +86,19 @@ public class SentinelConfig { | |||||
private static void initialize() { | private static void initialize() { | ||||
// Init default properties. | // Init default properties. | ||||
SentinelConfig.setConfig(CHARSET, DEFAULT_CHARSET); | |||||
SentinelConfig.setConfig(SINGLE_METRIC_FILE_SIZE, String.valueOf(DEFAULT_SINGLE_METRIC_FILE_SIZE)); | |||||
SentinelConfig.setConfig(TOTAL_METRIC_FILE_COUNT, String.valueOf(DEFAULT_TOTAL_METRIC_FILE_COUNT)); | |||||
SentinelConfig.setConfig(COLD_FACTOR, String.valueOf(DEFAULT_COLD_FACTOR)); | |||||
SentinelConfig.setConfig(STATISTIC_MAX_RT, String.valueOf(DEFAULT_STATISTIC_MAX_RT)); | |||||
setConfig(CHARSET, DEFAULT_CHARSET); | |||||
setConfig(SINGLE_METRIC_FILE_SIZE, String.valueOf(DEFAULT_SINGLE_METRIC_FILE_SIZE)); | |||||
setConfig(TOTAL_METRIC_FILE_COUNT, String.valueOf(DEFAULT_TOTAL_METRIC_FILE_COUNT)); | |||||
setConfig(COLD_FACTOR, String.valueOf(DEFAULT_COLD_FACTOR)); | |||||
setConfig(STATISTIC_MAX_RT, String.valueOf(DEFAULT_STATISTIC_MAX_RT)); | |||||
} | } | ||||
private static void loadProps() { | private static void loadProps() { | ||||
// Resolve app name. | |||||
AppNameUtil.resolveAppName(); | |||||
try { | |||||
String appName = AppNameUtil.getAppName(); | |||||
if (appName == null) { | |||||
appName = ""; | |||||
} | |||||
// We first retrieve the properties from the property file. | |||||
String fileName = LogBase.getLogBaseDir() + appName + ".properties"; | |||||
File file = new File(fileName); | |||||
if (file.exists()) { | |||||
RecordLog.info("[SentinelConfig] Reading config from " + fileName); | |||||
FileInputStream fis = new FileInputStream(fileName); | |||||
Properties fileProps = new Properties(); | |||||
fileProps.load(fis); | |||||
fis.close(); | |||||
for (Object key : fileProps.keySet()) { | |||||
SentinelConfig.setConfig((String)key, (String)fileProps.get(key)); | |||||
} | |||||
} | |||||
} catch (Throwable ioe) { | |||||
RecordLog.info(ioe.getMessage(), ioe); | |||||
Properties properties = SentinelConfigLoader.getProperties(); | |||||
for (Object key : properties.keySet()) { | |||||
setConfig((String) key, (String) properties.get(key)); | |||||
} | } | ||||
// JVM parameter override file config. | |||||
for (Map.Entry<Object, Object> entry : new CopyOnWriteArraySet<>(System.getProperties().entrySet())) { | |||||
String configKey = entry.getKey().toString(); | |||||
String configValue = entry.getValue().toString(); | |||||
String configValueOld = getConfig(configKey); | |||||
SentinelConfig.setConfig(configKey, configValue); | |||||
if (configValueOld != null) { | |||||
RecordLog.info("[SentinelConfig] JVM parameter overrides {0}: {1} -> {2}", configKey, configValueOld, configValue); | |||||
} | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -190,7 +155,7 @@ public class SentinelConfig { | |||||
return Long.parseLong(props.get(SINGLE_METRIC_FILE_SIZE)); | return Long.parseLong(props.get(SINGLE_METRIC_FILE_SIZE)); | ||||
} catch (Throwable throwable) { | } catch (Throwable throwable) { | ||||
RecordLog.warn("[SentinelConfig] Parse singleMetricFileSize fail, use default value: " | RecordLog.warn("[SentinelConfig] Parse singleMetricFileSize fail, use default value: " | ||||
+ DEFAULT_SINGLE_METRIC_FILE_SIZE, throwable); | |||||
+ DEFAULT_SINGLE_METRIC_FILE_SIZE, throwable); | |||||
return DEFAULT_SINGLE_METRIC_FILE_SIZE; | return DEFAULT_SINGLE_METRIC_FILE_SIZE; | ||||
} | } | ||||
} | } | ||||
@@ -200,7 +165,7 @@ public class SentinelConfig { | |||||
return Integer.parseInt(props.get(TOTAL_METRIC_FILE_COUNT)); | return Integer.parseInt(props.get(TOTAL_METRIC_FILE_COUNT)); | ||||
} catch (Throwable throwable) { | } catch (Throwable throwable) { | ||||
RecordLog.warn("[SentinelConfig] Parse totalMetricFileCount fail, use default value: " | RecordLog.warn("[SentinelConfig] Parse totalMetricFileCount fail, use default value: " | ||||
+ DEFAULT_TOTAL_METRIC_FILE_COUNT, throwable); | |||||
+ DEFAULT_TOTAL_METRIC_FILE_COUNT, throwable); | |||||
return DEFAULT_TOTAL_METRIC_FILE_COUNT; | return DEFAULT_TOTAL_METRIC_FILE_COUNT; | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,95 @@ | |||||
/* | |||||
* 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.config; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | |||||
import com.alibaba.csp.sentinel.util.AppNameUtil; | |||||
import com.alibaba.csp.sentinel.util.ConfigUtil; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
import java.io.File; | |||||
import java.util.Map; | |||||
import java.util.Properties; | |||||
import java.util.concurrent.CopyOnWriteArraySet; | |||||
import static com.alibaba.csp.sentinel.util.ConfigUtil.addSeparator; | |||||
/** | |||||
* <p> | |||||
* class responsible for loading the Sentinel Core configuration | |||||
* </p> | |||||
* | |||||
* @author lianglin | |||||
* @since 1.7.0 | |||||
*/ | |||||
public class SentinelConfigLoader { | |||||
private static final String DIR_NAME = "logs" + File.separator + "csp"; | |||||
private static final String USER_HOME = "user.home"; | |||||
public static final String SENTINEL_CONFIG = "csp.sentinel.config.file"; | |||||
private static String DEFAULT_SENTINEL_CONFIG_FILE = "classpath:sentinel.properties"; | |||||
private static Properties properties = new Properties(); | |||||
static { | |||||
load(); | |||||
} | |||||
private static void load() { | |||||
String fileName = System.getProperty(SENTINEL_CONFIG); | |||||
if (StringUtil.isBlank(fileName)) { | |||||
fileName = DEFAULT_SENTINEL_CONFIG_FILE; | |||||
} | |||||
Properties p = ConfigUtil.loadProperties(fileName); | |||||
//old version config file | |||||
if (p == null) { | |||||
String path = addSeparator(System.getProperty(USER_HOME)) + DIR_NAME + File.separator; | |||||
fileName = path + AppNameUtil.getAppName() + ".properties"; | |||||
File file = new File(fileName); | |||||
if (file.exists()) { | |||||
p = ConfigUtil.loadProperties(fileName); | |||||
} | |||||
} | |||||
if (p != null && !p.isEmpty()) { | |||||
properties.putAll(p); | |||||
} | |||||
for (Map.Entry<Object, Object> entry : new CopyOnWriteArraySet<>(System.getProperties().entrySet())) { | |||||
String configKey = entry.getKey().toString(); | |||||
String newConfigValue = entry.getValue().toString(); | |||||
String oldConfigValue = properties.getProperty(configKey); | |||||
properties.put(configKey, newConfigValue); | |||||
if (oldConfigValue != null) { | |||||
RecordLog.info("[SentinelConfig] JVM parameter overrides {0}: {1} -> {2}", configKey, oldConfigValue, newConfigValue); | |||||
} | |||||
} | |||||
} | |||||
public static Properties getProperties() { | |||||
return properties; | |||||
} | |||||
} |
@@ -15,14 +15,16 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.log; | package com.alibaba.csp.sentinel.log; | ||||
import com.alibaba.csp.sentinel.util.PidUtil; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.Properties; | |||||
import java.util.logging.Handler; | import java.util.logging.Handler; | ||||
import java.util.logging.Level; | import java.util.logging.Level; | ||||
import java.util.logging.Logger; | import java.util.logging.Logger; | ||||
import com.alibaba.csp.sentinel.util.PidUtil; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
import static com.alibaba.csp.sentinel.util.ConfigUtil.addSeparator; | |||||
/** | /** | ||||
* Default log base dir is ${user.home}/logs/csp/, we can use {@link #LOG_DIR} System property to override it. | * Default log base dir is ${user.home}/logs/csp/, we can use {@link #LOG_DIR} System property to override it. | ||||
@@ -34,67 +36,81 @@ import com.alibaba.csp.sentinel.util.StringUtil; | |||||
*/ | */ | ||||
public class LogBase { | public class LogBase { | ||||
public static final String LOG_CHARSET = "utf-8"; | |||||
// Output biz log(RecordLog,CommandCenterLog) to file | |||||
public static final String LOG_OUTPUT_TYPE_FILE = "file"; | |||||
// Output biz log(RecordLog,CommandCenterLog) to console | |||||
public static final String LOG_OUTPUT_TYPE_CONSOLE = "console"; | |||||
private static final String DIR_NAME = "logs" + File.separator + "csp"; | private static final String DIR_NAME = "logs" + File.separator + "csp"; | ||||
private static final String USER_HOME = "user.home"; | |||||
// Output type of biz log(RecordLog,CommandCenterLog) | |||||
public static final String LOG_OUTPUT_TYPE = "csp.sentinel.log.output.type"; | |||||
public static final String LOG_DIR = "csp.sentinel.log.dir"; | public static final String LOG_DIR = "csp.sentinel.log.dir"; | ||||
public static final String LOG_NAME_USE_PID = "csp.sentinel.log.use.pid"; | public static final String LOG_NAME_USE_PID = "csp.sentinel.log.use.pid"; | ||||
public static final String LOG_OUTPUT_TYPE = "csp.sentinel.log.output.type"; | |||||
public static final String LOG_CHARSET = "csp.sentinel.log.charset"; | |||||
public static final String USER_HOME = "user.home"; | |||||
/** | |||||
* Output biz log(RecordLog,CommandCenterLog) to file | |||||
*/ | |||||
public static final String LOG_OUTPUT_TYPE_FILE = "file"; | |||||
/** | |||||
* Output biz log(RecordLog,CommandCenterLog) to console | |||||
*/ | |||||
public static final String LOG_OUTPUT_TYPE_CONSOLE = "console"; | |||||
public static final String LOG_CHARSET_UTF8 = "utf-8"; | |||||
private static boolean logNameUsePid; | |||||
private static String logOutputType; | private static String logOutputType; | ||||
private static String logBaseDir; | private static String logBaseDir; | ||||
private static boolean logNameUsePid = false; | |||||
private static String logCharSet; | |||||
static { | static { | ||||
try { | try { | ||||
init(); | |||||
initialize(); | |||||
loadProperties(); | |||||
} catch (Throwable t) { | } catch (Throwable t) { | ||||
System.err.println("[LogBase] FATAL ERROR when initializing log class"); | System.err.println("[LogBase] FATAL ERROR when initializing log class"); | ||||
t.printStackTrace(); | t.printStackTrace(); | ||||
} | } | ||||
} | } | ||||
private static void init() { | |||||
logOutputType = System.getProperty(LOG_OUTPUT_TYPE); | |||||
private static void initialize() { | |||||
logNameUsePid = false; | |||||
logOutputType = LOG_OUTPUT_TYPE_FILE; | |||||
logBaseDir = addSeparator(System.getProperty(USER_HOME)) + DIR_NAME + File.separator; | |||||
logCharSet = LOG_CHARSET_UTF8; | |||||
} | |||||
// By default, output biz log(RecordLog,CommandCenterLog) to file | |||||
if (StringUtil.isBlank(logOutputType)) { | |||||
logOutputType = LOG_OUTPUT_TYPE_FILE; | |||||
} else if (!LOG_OUTPUT_TYPE_FILE.equalsIgnoreCase(logOutputType) && !LOG_OUTPUT_TYPE_CONSOLE.equalsIgnoreCase(logOutputType)) { | |||||
private static void loadProperties() { | |||||
Properties properties = LogConfigLoader.getProperties(); | |||||
logOutputType = properties.get(LOG_OUTPUT_TYPE) == null ? logOutputType : properties.getProperty(LOG_OUTPUT_TYPE); | |||||
if (!LOG_OUTPUT_TYPE_FILE.equalsIgnoreCase(logOutputType) && !LOG_OUTPUT_TYPE_CONSOLE.equalsIgnoreCase(logOutputType)) { | |||||
logOutputType = LOG_OUTPUT_TYPE_FILE; | logOutputType = LOG_OUTPUT_TYPE_FILE; | ||||
} | } | ||||
System.out.println("INFO: log out type is: " + logOutputType); | |||||
// first use -D, then use user home. | |||||
String logDir = System.getProperty(LOG_DIR); | |||||
if (logDir == null || logDir.isEmpty()) { | |||||
logDir = System.getProperty(USER_HOME); | |||||
logDir = addSeparator(logDir) + DIR_NAME + File.separator; | |||||
} | |||||
logDir = addSeparator(logDir); | |||||
File dir = new File(logDir); | |||||
logCharSet = properties.getProperty(LOG_CHARSET) == null ? logCharSet : properties.getProperty(LOG_CHARSET); | |||||
System.out.println("INFO: log charset is: " + logCharSet); | |||||
logBaseDir = properties.getProperty(LOG_DIR) == null ? logBaseDir : properties.getProperty(LOG_DIR); | |||||
addSeparator(logBaseDir); | |||||
File dir = new File(logBaseDir); | |||||
if (!dir.exists()) { | if (!dir.exists()) { | ||||
if (!dir.mkdirs()) { | if (!dir.mkdirs()) { | ||||
System.err.println("ERROR: create log base dir error: " + logDir); | |||||
System.err.println("ERROR: create log base dir error: " + logBaseDir); | |||||
} | } | ||||
} | } | ||||
// logBaseDir must end with File.separator | |||||
logBaseDir = logDir; | |||||
System.out.println("INFO: log base dir is: " + logBaseDir); | System.out.println("INFO: log base dir is: " + logBaseDir); | ||||
String usePid = System.getProperty(LOG_NAME_USE_PID, ""); | |||||
String usePid = properties.getProperty(LOG_NAME_USE_PID); | |||||
logNameUsePid = "true".equalsIgnoreCase(usePid); | logNameUsePid = "true".equalsIgnoreCase(usePid); | ||||
System.out.println("INFO: log name use pid is: " + logNameUsePid); | System.out.println("INFO: log name use pid is: " + logNameUsePid); | ||||
} | } | ||||
/** | /** | ||||
* Whether log file name should contain pid. This switch is configured by {@link #LOG_NAME_USE_PID} System property. | * Whether log file name should contain pid. This switch is configured by {@link #LOG_NAME_USE_PID} System property. | ||||
* | * | ||||
@@ -104,13 +120,34 @@ public class LogBase { | |||||
return logNameUsePid; | return logNameUsePid; | ||||
} | } | ||||
private static String addSeparator(String logDir) { | |||||
if (!logDir.endsWith(File.separator)) { | |||||
logDir += File.separator; | |||||
} | |||||
return logDir; | |||||
/** | |||||
* Get log file base directory path, the returned path is guaranteed end with {@link File#separator} | |||||
* | |||||
* @return log file base directory path. | |||||
*/ | |||||
public static String getLogBaseDir() { | |||||
return logBaseDir; | |||||
} | |||||
/** | |||||
* Get log file output type the default value is "file" | |||||
* | |||||
* @return | |||||
*/ | |||||
public static String getLogOutputType() { | |||||
return logOutputType; | |||||
} | |||||
/** | |||||
* Get log file charSet the default value is utf-8 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static String getLogCharset() { | |||||
return logCharSet; | |||||
} | } | ||||
protected static void log(Logger logger, Handler handler, Level level, String detail, Object... params) { | protected static void log(Logger logger, Handler handler, Level level, String detail, Object... params) { | ||||
if (detail == null) { | if (detail == null) { | ||||
return; | return; | ||||
@@ -131,14 +168,6 @@ public class LogBase { | |||||
logger.log(level, detail, throwable); | logger.log(level, detail, throwable); | ||||
} | } | ||||
/** | |||||
* Get log file base directory path, the returned path is guaranteed end with {@link File#separator} | |||||
* | |||||
* @return log file base directory path. | |||||
*/ | |||||
public static String getLogBaseDir() { | |||||
return logBaseDir; | |||||
} | |||||
protected static Handler makeLogger(String logName, Logger heliumRecordLog) { | protected static Handler makeLogger(String logName, Logger heliumRecordLog) { | ||||
CspFormatter formatter = new CspFormatter(); | CspFormatter formatter = new CspFormatter(); | ||||
@@ -155,7 +184,7 @@ public class LogBase { | |||||
try { | try { | ||||
handler = new DateFileLogHandler(fileName + ".%d", 1024 * 1024 * 200, 4, true); | handler = new DateFileLogHandler(fileName + ".%d", 1024 * 1024 * 200, 4, true); | ||||
handler.setFormatter(formatter); | handler.setFormatter(formatter); | ||||
handler.setEncoding(LOG_CHARSET); | |||||
handler.setEncoding(logCharSet); | |||||
} catch (IOException e) { | } catch (IOException e) { | ||||
e.printStackTrace(); | e.printStackTrace(); | ||||
} | } | ||||
@@ -164,7 +193,7 @@ public class LogBase { | |||||
try { | try { | ||||
handler = new ConsoleHandler(); | handler = new ConsoleHandler(); | ||||
handler.setFormatter(formatter); | handler.setFormatter(formatter); | ||||
handler.setEncoding(LOG_CHARSET); | |||||
handler.setEncoding(logCharSet); | |||||
} catch (IOException e) { | } catch (IOException e) { | ||||
e.printStackTrace(); | e.printStackTrace(); | ||||
} | } | ||||
@@ -179,4 +208,6 @@ public class LogBase { | |||||
heliumRecordLog.setLevel(Level.ALL); | heliumRecordLog.setLevel(Level.ALL); | ||||
return handler; | return handler; | ||||
} | } | ||||
} | } |
@@ -0,0 +1,78 @@ | |||||
/* | |||||
* 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.log; | |||||
import com.alibaba.csp.sentinel.util.ConfigUtil; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
import java.util.Map; | |||||
import java.util.Properties; | |||||
import java.util.concurrent.CopyOnWriteArraySet; | |||||
/** | |||||
* <p> | |||||
* class responsible for loading the Log configuration. | |||||
* </p> | |||||
* | |||||
* @author lianglin | |||||
* @since 1.7.0 | |||||
*/ | |||||
public class LogConfigLoader { | |||||
public static final String LOG_CONFIG = "csp.sentinel.config.file"; | |||||
private static final String DEFAULT_LOG_CONFIG_FILE = "classpath:sentinel.properties"; | |||||
private static final Properties properties = new Properties(); | |||||
static { | |||||
load(); | |||||
} | |||||
private static void load() { | |||||
String file = System.getProperty(LOG_CONFIG); | |||||
if (StringUtil.isBlank(file)) { | |||||
file = DEFAULT_LOG_CONFIG_FILE; | |||||
} | |||||
Properties p = ConfigUtil.loadProperties(file); | |||||
if (p != null && !p.isEmpty()) { | |||||
properties.putAll(p); | |||||
} | |||||
CopyOnWriteArraySet<Map.Entry<Object, Object>> copy = new CopyOnWriteArraySet<>(System.getProperties().entrySet()); | |||||
for (Map.Entry<Object, Object> entry : copy) { | |||||
String configKey = entry.getKey().toString(); | |||||
String newConfigValue = entry.getValue().toString(); | |||||
String oldConfigValue = properties.getProperty(configKey); | |||||
properties.put(configKey, newConfigValue); | |||||
if (oldConfigValue != null) { | |||||
System.out.println("[LogConfig] JVM parameter overrides: " + configKey + " " + oldConfigValue + " -> " + newConfigValue); | |||||
} | |||||
} | |||||
} | |||||
public static Properties getProperties() { | |||||
return properties; | |||||
} | |||||
} |
@@ -15,10 +15,10 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.util; | package com.alibaba.csp.sentinel.util; | ||||
import java.io.File; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import java.io.File; | |||||
/** | /** | ||||
* Util class for getting application name. This class uses the flowing order to get app's name: | * Util class for getting application name. This class uses the flowing order to get app's name: | ||||
* | * | ||||
@@ -0,0 +1,147 @@ | |||||
/* | |||||
* 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 java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.InputStream; | |||||
import java.net.URL; | |||||
import java.util.ArrayList; | |||||
import java.util.Enumeration; | |||||
import java.util.List; | |||||
import java.util.Properties; | |||||
/** | |||||
* <p> | |||||
* util for loading config | |||||
* </p> | |||||
* | |||||
* @author lianglin | |||||
* @since 1.7.0 | |||||
*/ | |||||
public final class ConfigUtil { | |||||
public static final String CLASSPATH_FILE_FLAG = "classpath:"; | |||||
/** | |||||
* Return null if the file not exist | |||||
* | |||||
* @param fileName | |||||
* @return | |||||
*/ | |||||
public static Properties loadProperties(String fileName) { | |||||
if (StringUtil.isNotBlank(fileName)) { | |||||
if (fileName.startsWith(File.separator)) { | |||||
return loadPropertiesFromAbsoluteFile(fileName); | |||||
} else if (fileName.startsWith(CLASSPATH_FILE_FLAG)) { | |||||
return loadPropertiesFromClasspathFile(fileName); | |||||
} else { | |||||
return loadPropertiesFromRelativeFile(fileName); | |||||
} | |||||
} else { | |||||
return null; | |||||
} | |||||
} | |||||
private static Properties loadPropertiesFromAbsoluteFile(String fileName) { | |||||
Properties properties = null; | |||||
try { | |||||
File file = new File(fileName); | |||||
if (!file.exists()) { | |||||
return null; | |||||
} | |||||
FileInputStream input = new FileInputStream(file); | |||||
try { | |||||
properties = new Properties(); | |||||
properties.load(input); | |||||
} finally { | |||||
input.close(); | |||||
} | |||||
} catch (Throwable e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return properties; | |||||
} | |||||
private static Properties loadPropertiesFromClasspathFile(String fileName) { | |||||
fileName = fileName.substring(CLASSPATH_FILE_FLAG.length()).trim(); | |||||
List<URL> list = new ArrayList<URL>(); | |||||
try { | |||||
Enumeration<URL> urls = getClassLoader().getResources(fileName); | |||||
list = new ArrayList<URL>(); | |||||
while (urls.hasMoreElements()) { | |||||
list.add(urls.nextElement()); | |||||
} | |||||
} catch (Throwable e) { | |||||
e.printStackTrace(); | |||||
} | |||||
if (list.isEmpty()) { | |||||
return null; | |||||
} | |||||
Properties properties = new Properties(); | |||||
for (URL url : list) { | |||||
try { | |||||
Properties p = new Properties(); | |||||
InputStream input = url.openStream(); | |||||
if (input != null) { | |||||
try { | |||||
p.load(input); | |||||
properties.putAll(p); | |||||
} finally { | |||||
try { | |||||
input.close(); | |||||
} catch (Throwable t) { | |||||
} | |||||
} | |||||
} | |||||
} catch (Throwable e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
return properties; | |||||
} | |||||
private static Properties loadPropertiesFromRelativeFile(String fileName) { | |||||
String userDir = System.getProperty("user.dir"); | |||||
String realFilePath = addSeparator(userDir) + fileName; | |||||
return loadPropertiesFromAbsoluteFile(realFilePath); | |||||
} | |||||
private static ClassLoader getClassLoader() { | |||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); | |||||
if (classLoader == null) { | |||||
classLoader = ConfigUtil.class.getClassLoader(); | |||||
} | |||||
return classLoader; | |||||
} | |||||
public static String addSeparator(String dir) { | |||||
if (!dir.endsWith(File.separator)) { | |||||
dir += File.separator; | |||||
} | |||||
return dir; | |||||
} | |||||
} |
@@ -1,7 +1,15 @@ | |||||
package com.alibaba.csp.sentinel.config; | package com.alibaba.csp.sentinel.config; | ||||
import org.junit.Assert; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.io.BufferedWriter; | |||||
import java.io.File; | |||||
import java.io.FileWriter; | |||||
import java.io.IOException; | |||||
import static com.alibaba.csp.sentinel.config.SentinelConfig.*; | |||||
import static com.alibaba.csp.sentinel.util.ConfigUtil.addSeparator; | |||||
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
/** | /** | ||||
@@ -20,7 +28,7 @@ public class SentinelConfigTest { | |||||
assertEquals(SentinelConfig.DEFAULT_STATISTIC_MAX_RT, SentinelConfig.statisticMaxRt()); | assertEquals(SentinelConfig.DEFAULT_STATISTIC_MAX_RT, SentinelConfig.statisticMaxRt()); | ||||
} | } | ||||
// add JVM parameter | |||||
// add JVM parameter | |||||
// -Dcsp.sentinel.charset=gbk | // -Dcsp.sentinel.charset=gbk | ||||
// -Dcsp.sentinel.metric.file.single.size=104857600 | // -Dcsp.sentinel.metric.file.single.size=104857600 | ||||
// -Dcsp.sentinel.metric.file.total.count=10 | // -Dcsp.sentinel.metric.file.total.count=10 | ||||
@@ -58,4 +66,51 @@ public class SentinelConfigTest { | |||||
SentinelConfig.setConfig(SentinelConfig.COLD_FACTOR, "4"); | SentinelConfig.setConfig(SentinelConfig.COLD_FACTOR, "4"); | ||||
assertEquals(4, SentinelConfig.coldFactor()); | assertEquals(4, SentinelConfig.coldFactor()); | ||||
} | } | ||||
//add Jvm parameter | |||||
//-Dcsp.sentinel.config.file=sentinel-propertiesTest.properties | |||||
//-Dcsp.sentinel.flow.cold.factor=5 | |||||
//-Dcsp.sentinel.statistic.max.rt=1000 | |||||
//@Test | |||||
public void testLoadProperties() throws IOException { | |||||
File file = null; | |||||
String fileName = "sentinel-propertiesTest.properties"; | |||||
try { | |||||
file = new File(addSeparator(System.getProperty("user.dir")) + "target/classes/" + fileName); | |||||
if (!file.exists()) { | |||||
file.createNewFile(); | |||||
} | |||||
BufferedWriter out = new BufferedWriter(new FileWriter(file)); | |||||
out.write(buildPropertyStr(CHARSET, "utf-8")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(SINGLE_METRIC_FILE_SIZE, "1000")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(TOTAL_METRIC_FILE_COUNT, "20")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(COLD_FACTOR, "123")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(STATISTIC_MAX_RT, "6000")); | |||||
out.flush(); | |||||
out.close(); | |||||
Assert.assertTrue(SentinelConfig.getConfig(CHARSET).equals("utf-8")); | |||||
Assert.assertTrue(SentinelConfig.getConfig(SINGLE_METRIC_FILE_SIZE).equals("1000")); | |||||
Assert.assertTrue(SentinelConfig.getConfig(TOTAL_METRIC_FILE_COUNT).equals("20")); | |||||
Assert.assertTrue(SentinelConfig.getConfig(COLD_FACTOR).equals("5")); | |||||
Assert.assertTrue(SentinelConfig.getConfig(STATISTIC_MAX_RT).equals("1000")); | |||||
} finally { | |||||
if (file != null) { | |||||
file.delete(); | |||||
} | |||||
} | |||||
} | |||||
private String buildPropertyStr(String key, String value) { | |||||
return key + "=" + value; | |||||
} | |||||
} | } |
@@ -0,0 +1,79 @@ | |||||
/* | |||||
* 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.log; | |||||
import org.junit.Assert; | |||||
import java.io.BufferedWriter; | |||||
import java.io.File; | |||||
import java.io.FileWriter; | |||||
import java.io.IOException; | |||||
import static com.alibaba.csp.sentinel.log.LogBase.*; | |||||
import static com.alibaba.csp.sentinel.util.ConfigUtil.addSeparator; | |||||
/** | |||||
* @author lianglin | |||||
* @since 1.7.0 | |||||
*/ | |||||
public class LogBaseTest { | |||||
//add Jvm parameter | |||||
//-Dcsp.sentinel.config.file=log-propertiesTest.properties | |||||
//-Dcsp.sentinel.log.charset="utf-8" | |||||
//-Dcsp.sentinel.log.output.type="file" | |||||
//@Test | |||||
public void testLoadProperties() throws IOException { | |||||
File file = null; | |||||
String fileName = "log-propertiesTest.properties"; | |||||
try { | |||||
file = new File(addSeparator(System.getProperty("user.dir")) + "target/classes/" + fileName); | |||||
if (!file.exists()) { | |||||
file.createNewFile(); | |||||
} | |||||
BufferedWriter out = new BufferedWriter(new FileWriter(file)); | |||||
out.write(buildPropertyStr(LOG_DIR, "/data/logs/")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(LOG_NAME_USE_PID, "true")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(LOG_OUTPUT_TYPE, "console")); | |||||
out.write("\n"); | |||||
out.write(buildPropertyStr(LOG_CHARSET, "gbk")); | |||||
out.flush(); | |||||
out.close(); | |||||
//test will make dir | |||||
//Assert.assertTrue(LogBase.getLogBaseDir().equals("/data/logs/")); | |||||
Assert.assertTrue(LogBase.isLogNameUsePid()); | |||||
Assert.assertTrue(LogBase.getLogOutputType().equals("file")); | |||||
Assert.assertTrue(LogBase.getLogCharset().equals("utf-8")); | |||||
} finally { | |||||
if (file != null) { | |||||
file.delete(); | |||||
} | |||||
} | |||||
} | |||||
private String buildPropertyStr(String key, String value) { | |||||
return key + "=" + value; | |||||
} | |||||
} |
@@ -0,0 +1,84 @@ | |||||
/* | |||||
* 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 org.junit.Assert; | |||||
import org.junit.Test; | |||||
import java.io.BufferedWriter; | |||||
import java.io.File; | |||||
import java.io.FileWriter; | |||||
import java.io.IOException; | |||||
import java.util.Properties; | |||||
import static com.alibaba.csp.sentinel.log.LogBase.LOG_DIR; | |||||
import static com.alibaba.csp.sentinel.log.LogBase.LOG_OUTPUT_TYPE; | |||||
import static com.alibaba.csp.sentinel.util.ConfigUtil.addSeparator; | |||||
/** | |||||
* @author lianglin | |||||
* @since 1.7.0 | |||||
*/ | |||||
public class ConfigUtilTest { | |||||
@Test | |||||
public void testLoadProperties() throws IOException { | |||||
File file = null; | |||||
String logOutputType = "utf-8", | |||||
dir = "/data/logs/", | |||||
fileName = "propertiesTest.properties"; | |||||
try { | |||||
String userDir = System.getProperty("user.dir"); | |||||
file = new File(addSeparator(userDir) + "target/classes/" + fileName); | |||||
if (!file.exists()) { | |||||
file.createNewFile(); | |||||
} | |||||
BufferedWriter out = new BufferedWriter(new FileWriter(file)); | |||||
out.write(LOG_OUTPUT_TYPE + "=" + logOutputType); | |||||
out.write("\n"); | |||||
out.write(LOG_DIR + "=" + dir); | |||||
out.flush(); | |||||
out.close(); | |||||
//Load from absolutePath | |||||
Properties properties = ConfigUtil.loadProperties(file.getAbsolutePath()); | |||||
Assert.assertTrue(logOutputType.equals(properties.getProperty(LOG_OUTPUT_TYPE))); | |||||
Assert.assertTrue(dir.equals(properties.getProperty(LOG_DIR))); | |||||
//Load from classPath | |||||
properties = ConfigUtil.loadProperties(ConfigUtil.CLASSPATH_FILE_FLAG + fileName); | |||||
Assert.assertTrue(logOutputType.equals(properties.getProperty(LOG_OUTPUT_TYPE))); | |||||
Assert.assertTrue(dir.equals(properties.getProperty(LOG_DIR))); | |||||
//Load from relativePath | |||||
properties = ConfigUtil.loadProperties("target/classes/" + fileName); | |||||
Assert.assertTrue(logOutputType.equals(properties.getProperty(LOG_OUTPUT_TYPE))); | |||||
Assert.assertTrue(dir.equals(properties.getProperty(LOG_DIR))); | |||||
} finally { | |||||
if (file != null) { | |||||
file.delete(); | |||||
} | |||||
} | |||||
} | |||||
} |