提交 f147e8df 编写于 作者: L leon.li

Merge branch 'develop'

......@@ -7,3 +7,7 @@
.*
/*.bat
!.travis.yml
cat-client/src/main/resources/com/dianping/cat/configuration/client/config.xsd
cat-client/src/main/resources/com/dianping/cat/status/model/status.xsd
......@@ -10,17 +10,6 @@
<name>broker-service</name>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.unidal.eunit</groupId>
<artifactId>EunitTestFwk</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>foundation-service</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-core</artifactId>
......@@ -87,11 +76,6 @@
<version>2.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>dal-jdbc</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
......
package com.dianping.cat.broker.api.app;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import org.codehaus.plexus.logging.LogEnabled;
......@@ -16,7 +18,7 @@ import com.dianping.cat.config.app.AppDataService;
public class AppDataConsumer implements Initializable, LogEnabled {
public static final long DURATION = 5 * 60 * 1000L;
@Inject
private AppDataService m_appDataService;
......@@ -99,12 +101,15 @@ public class AppDataConsumer implements Initializable, LogEnabled {
private class BucketThreadController implements Task {
private SimpleDateFormat m_sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
private void closeLastTask(long currentDuration) {
Long last = new Long(currentDuration - DURATION);
BucketHandler lastBucketHandler = m_tasks.get(last);
if (lastBucketHandler != null) {
lastBucketHandler.shutdown();
m_logger.info("closed bucket handler ,time " + m_sdf.format(new Date(currentDuration)));
}
}
......@@ -126,7 +131,7 @@ public class AppDataConsumer implements Initializable, LogEnabled {
try {
long currentDuration = curTime - curTime % DURATION;
removeLastLastTask(currentDuration);
closeLastTask(currentDuration);
startCurrentTask(currentDuration);
......@@ -151,21 +156,26 @@ public class AppDataConsumer implements Initializable, LogEnabled {
Long cur = new Long(currentDuration);
if (m_tasks.get(cur) == null) {
BucketHandler curBucketHandler = new BucketHandler(cur, m_appDataService);
m_logger.info("starting bucket handler ,time " + m_sdf.format(new Date(currentDuration)));
Threads.forGroup("Cat").start(curBucketHandler);
m_tasks.put(cur, curBucketHandler);
m_logger.info("started bucket handler ,time " + m_sdf.format(new Date(currentDuration)));
}
}
private void startNextTask(long currentDuration) {
Long next = new Long(currentDuration + DURATION);
if (m_tasks.get(next) == null) {
BucketHandler nextBucketHandler = new BucketHandler(next, m_appDataService);
m_logger.info("starting bucket handler ,time " + m_sdf.format(new Date(next)));
Threads.forGroup("Cat").start(nextBucketHandler);
m_tasks.put(next, nextBucketHandler);
m_logger.info("started bucket handler ,time " + m_sdf.format(new Date(next)));
}
}
}
}
......@@ -43,7 +43,9 @@ public class BucketHandler implements Task {
int batchSize = 100;
for (Entry<Integer, HashMap<String, AppData>> outerEntry : m_mergedData.entrySet()) {
for (Entry<String, AppData> entry : outerEntry.getValue().entrySet()) {
HashMap<String, AppData> value = outerEntry.getValue();
for (Entry<String, AppData> entry : value.entrySet()) {
AppData appData = entry.getValue();
AppDataCommand proto = new AppDataCommand();
......@@ -75,7 +77,14 @@ public class BucketHandler implements Task {
private void batchInsert(List<AppDataCommand> appDataCommands) {
try {
m_appDataService.insert((AppDataCommand[]) appDataCommands.toArray());
int length = appDataCommands.size();
AppDataCommand[] array = new AppDataCommand[length];
for (int i = 0; i < length; i++) {
array[i] = appDataCommands.get(i);
}
m_appDataService.insert(array);
} catch (Exception e) {
Cat.logError(e);
}
......@@ -87,13 +96,11 @@ public class BucketHandler implements Task {
@Override
public String getName() {
return "BucketHandler";
return "BucketHandler-" + m_startTime;
}
public boolean isActive() {
synchronized (this) {
return m_isActive;
}
return m_isActive;
}
private void processEntity(AppData appData) {
......@@ -137,7 +144,11 @@ public class BucketHandler implements Task {
AppData appData = m_appDataQueue.poll();
if (appData != null) {
processEntity(appData);
try {
processEntity(appData);
} catch (Exception e) {
Cat.logError(e);
}
}
}
......@@ -156,9 +167,7 @@ public class BucketHandler implements Task {
@Override
public void shutdown() {
synchronized (this) {
m_isActive = false;
}
m_isActive = false;
}
}
......@@ -156,7 +156,6 @@ public class MonitorManager implements Initializable, LogEnabled {
buildMessage(entity, url, ipInfo);
} else {
Cat.logEvent("ip", "notFound", Event.SUCCESS, ip);
m_logger.error(String.format("can't find ip for %s", ip));
}
t.setStatus(Transaction.SUCCESS);
} catch (Exception e) {
......
......@@ -66,9 +66,9 @@ public class Handler implements PageHandler<Context>, LogEnabled {
String version = payload.getVersion();
if (userIp != null) {
if (version.equals("1")) {
if ("1".equals(version)) {
processVersion1(payload, request, userIp);
} else if (version.equals("2")) {
} else if ("2".equals(version)) {
processVersion2(payload, request, userIp);
}
} else {
......@@ -104,8 +104,10 @@ public class Handler implements PageHandler<Context>, LogEnabled {
entity.setErrorCode(errorCode);
entity.setIp(userIp);
if (payload.getVersion().equals("1")) {
if ("200".equals(httpStatus)) {
entity.setCount(10);
} else {
entity.setCount(1);
}
m_manager.offer(entity);
}
......
<app-config>
<config-item id="网络类型">
<item id="1" name="WIFI"></item>
<item id="2" name="2G"></item>
<item id="3" name="3G"></item>
<item id="4" name="4G"></item>
</config-item>
<config-item id="运营商">
<item id="1" name="中国移动"></item>
<item id="2" name="中国联通"></item>
<item id="3" name="中国电信"></item>
<item id="4" name="中国铁通"></item>
</config-item>
<config-item id="版本">
<item id="1" name="1.0"></item>
<item id="2" name="1.1"></item>
</config-item>
<config-item id="平台">
<item id="1" name="andriod"></item>
<item id="2" name="ios"></item>
</config-item>
<config-item id="城市">
<item id="1" name="上海市"></item>
<item id="2" name="安徽省"></item>
<item id="3" name="北京市"></item>
<item id="4" name="重庆市"></item>
<item id="5" name="福建省"></item>
<item id="6" name="甘肃省"></item>
<item id="7" name="广东省"></item>
<item id="8" name="广西壮族自治区"></item>
<item id="9" name="贵州省"></item>
<item id="10" name="海南省"></item>
<item id="11" name="河北省"></item>
<item id="12" name="河南省"></item>
<item id="13" name="黑龙江省"></item>
<item id="14" name="湖北省"></item>
<item id="15" name="湖南省"></item>
<item id="16" name="吉林省"></item>
<item id="17" name="江苏省"></item>
<item id="18" name="江西省"></item>
<item id="19" name="辽宁省"></item>
<item id="20" name="内蒙古自治区"></item>
<item id="21" name="宁夏回族自治区"></item>
<item id="22" name="青海省"></item>
<item id="23" name="山东省"></item>
<item id="24" name="山西省"></item>
<item id="25" name="陕西省"></item>
<item id="26" name="四川省"></item>
<item id="27" name="天津市"></item>
<item id="28" name="西藏自治区"></item>
<item id="29" name="香港特别行政区"></item>
<item id="30" name="新疆维吾尔自治区"></item>
<item id="31" name="云南省"></item>
<item id="32" name="浙江省"></item>
</config-item>
<config-item id="连接类型">
<item id="1" name="长连接"></item>
<item id="2" name="短连接"></item>
</config-item>
<command id="1" name="http://www.dianping.com/">
<code id="1" name="成功返回" status="0"></code>
<code id="2" name="参数错误" status="1"></code>
<code id="3" name="非常字符" status="1"></code>
</command>
</app-config>
\ No newline at end of file
......@@ -17,7 +17,7 @@
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>foundation-service</artifactId>
<version>2.0.4</version>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.unidal.webres</groupId>
......
......@@ -16,6 +16,7 @@ import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.dal.jdbc.DalException;
import org.unidal.dal.jdbc.DalNotFoundException;
import org.unidal.helper.Files;
import org.unidal.helper.Threads;
import org.unidal.helper.Threads.Task;
......@@ -168,6 +169,8 @@ public class DomainManager implements Initializable, LogEnabled {
} else {
return null;
}
} catch (DalNotFoundException e) {
// ignore
} catch (DalException e) {
Cat.logError(e);
}
......
package com.dianping.cat.config.app;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.unidal.lookup.util.StringUtils;
import com.dianping.cat.Cat;
public class QueryEntity {
......@@ -32,19 +33,27 @@ public class QueryEntity {
try {
m_date = sdf.parse(strs[0]);
m_command = Integer.parseInt(strs[1]);
m_code = Integer.parseInt(strs[2]);
m_network = Integer.parseInt(strs[3]);
m_version = Integer.parseInt(strs[4]);
m_channel = Integer.parseInt(strs[5]);
m_platfrom = Integer.parseInt(strs[6]);
m_city = Integer.parseInt(strs[7]);
m_operator = Integer.parseInt(strs[8]);
} catch (ParseException e) {
m_command = parseValue(strs[1]);
m_code = parseValue(strs[2]);
m_network = parseValue(strs[3]);
m_version = parseValue(strs[4]);
m_channel = parseValue(strs[5]);
m_platfrom = parseValue(strs[6]);
m_city = parseValue(strs[7]);
m_operator = parseValue(strs[8]);
} catch (Exception e) {
Cat.logError(e);
}
}
private int parseValue(String str) {
if (StringUtils.isEmpty(str)) {
return -1;
} else {
return Integer.parseInt(str);
}
}
public Date getDate() {
return m_date;
}
......@@ -118,10 +127,10 @@ public class QueryEntity {
}
@Override
public String toString() {
return "QueryEntity [m_date=" + m_date + ", m_command=" + m_command + ", m_code=" + m_code + ", m_network="
+ m_network + ", m_version=" + m_version + ", m_channel=" + m_channel + ", m_platfrom=" + m_platfrom
+ ", m_city=" + m_city + ", m_operator=" + m_operator + "]";
}
public String toString() {
return "QueryEntity [m_date=" + m_date + ", m_command=" + m_command + ", m_code=" + m_code + ", m_network="
+ m_network + ", m_version=" + m_version + ", m_channel=" + m_channel + ", m_platfrom=" + m_platfrom
+ ", m_city=" + m_city + ", m_operator=" + m_operator + "]";
}
}
......@@ -17,11 +17,6 @@
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>foundation-service</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-consumer</artifactId>
......@@ -154,14 +149,15 @@
${basedir}/src/main/resources/META-INF/dal/model/heavy-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/utilization-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/domainGroup-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/metric-group-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/metric-group-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/metric-aggregation-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/netgraph-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/alert-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/monitor-rules-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/alertconfig-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/alertsummary-manifest.xml,
</manifest>
${basedir}/src/main/resources/META-INF/dal/model/alert-type-manifest.xml,
</manifest>
</configuration>
</execution>
<execution>
......@@ -202,20 +198,20 @@
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<contextPath>/cat</contextPath>
<defaultsDescriptor>src/main/webapp/WEB-INF/web.xml</defaultsDescriptor>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>2281</port>
<maxIdleTime>500000</maxIdleTime>
</connector>
</connectors>
</configuration>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<contextPath>/cat</contextPath>
<defaultsDescriptor>src/main/webapp/WEB-INF/web.xml</defaultsDescriptor>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>2281</port>
<maxIdleTime>500000</maxIdleTime>
</connector>
</connectors>
</configuration>
</plugin>
</plugins>
</build>
......
......@@ -53,8 +53,7 @@ com.dianping.cat.report.page.system.Handler.class,
com.dianping.cat.report.page.cdn.Handler.class,
com.dianping.cat.report.page.app.Handler.class,
com.dianping.cat.report.page.app.Handler.class
})
public class ReportModule extends AbstractModule {
......
......@@ -21,7 +21,7 @@ public enum ReportPage implements Page {
DASHBOARD("dashboard", "dashboard", "Dashboard", "Dashboard", false),
MATRIX("matrix", "matrix", "Matrix", "Matrix", true),
MATRIX("matrix", "matrix", "Matrix", "Matrix", false),
CROSS("cross", "cross", "Cross", "Cross", true),
......@@ -37,23 +37,21 @@ public enum ReportPage implements Page {
EXTERNALERROR("externalError", "externalError", "externalError", "ExternalError", true),
STATISTICS("statistics", "statistics", "Statistics", "Statistics", true),
STATISTICS("statistics", "statistics", "Statistics", "Statistics", false),
ALTERATION("alteration", "alteration", "Change", "Alteration", true),
ALTERATION("alteration", "alteration", "Change", "Alteration", false),
MONITOR("monitor", "monitor", "Monitor", "Monitor", true),
NETWORK("network", "network", "Network", "Network", true),
NETWORK("network", "network", "Network", "Network", false),
USERMONITOR("userMonitor", "userMonitor", "Monitor", "UserMonitor", true),
SYSTEM("system", "system", "System", "System", true),
SYSTEM("system", "system", "System", "System", false),
CDN("cdn", "cdn", "Cdn", "Cdn", true),
CDN("cdn", "cdn", "Cdn", "Cdn", false),
APP("app", "app", "App", "App", true),
SUMMARY("summary", "summary", "Summary", "Summary", true);
APP("app", "app", "App", "App", true);
private String m_name;
......
......@@ -12,6 +12,7 @@ import com.dianping.cat.config.app.AppConfigManager;
import com.dianping.cat.config.app.QueryEntity;
import com.dianping.cat.report.ReportPage;
import com.dianping.cat.report.page.LineChart;
import com.dianping.cat.report.page.PayloadNormalizer;
import com.dianping.cat.report.page.app.graph.AppGraphCreator;
public class Handler implements PageHandler<Context> {
......@@ -24,6 +25,9 @@ public class Handler implements PageHandler<Context> {
@Inject
private AppGraphCreator m_appGraphCreator;
@Inject
private PayloadNormalizer m_normalizePayload;
@Override
@PayloadMeta(Payload.class)
@InboundActionMeta(name = "app")
......@@ -35,6 +39,7 @@ public class Handler implements PageHandler<Context> {
@OutboundActionMeta(name = "app")
public void handleOutbound(Context ctx) throws ServletException, IOException {
Model model = new Model(ctx);
Payload payload = ctx.getPayload();
model.setAction(Action.VIEW);
model.setPage(ReportPage.APP);
......@@ -45,8 +50,8 @@ public class Handler implements PageHandler<Context> {
model.setPlatforms(m_manager.queryConfigItem(AppConfigManager.PLATFORM));
model.setVersions(m_manager.queryConfigItem(AppConfigManager.VERSION));
model.setCommands(m_manager.queryCommands());
Payload payload = ctx.getPayload();
m_normalizePayload.normalize(model, payload);
QueryEntity entity1 = payload.getQueryEntity1();
QueryEntity entity2 = payload.getQueryEntity2();
String type = payload.getType();
......
......@@ -41,7 +41,7 @@ public class AlertExceptionBuilder {
double totalWarnLimit = totalLimitPair.getKey();
double totalErrorLimit = totalLimitPair.getValue();
double totalException = 0;
for (Entry<String, Double> entry : item.getException().entrySet()) {
String exceptionName = entry.getKey();
......@@ -138,7 +138,7 @@ public class AlertExceptionBuilder {
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date());
sb.append("[CAT异常告警] [项目: ").append(domain).append("] : ");
sb.append(exceptions).append("[时间: ").append(time).append("]");
sb.append(exceptions).append("[时间: ").append(time).append("]").append("\n");
sb.append(contactInfo);
return sb.toString();
......
......@@ -24,9 +24,9 @@ public class NavigationBar {
ReportPage.METRIC,
ReportPage.USERMONITOR,
ReportPage.APP,
ReportPage.TRANSACTION,
ReportPage.EVENT,
......@@ -39,10 +39,12 @@ public class NavigationBar {
ReportPage.CACHE,
ReportPage.MATRIX,
ReportPage.DEPENDENCY,
ReportPage.STATE,
ReportPage.MATRIX,
ReportPage.NETWORK,
ReportPage.CDN,
......@@ -51,11 +53,12 @@ public class NavigationBar {
ReportPage.ALTERATION,
ReportPage.STATE,
ReportPage.STATISTICS,
SystemPage.ALARM,
ReportPage.LOGVIEW,
};
SystemPage.CONFIG,
ReportPage.LOGVIEW, };
}
}
......@@ -5,11 +5,11 @@ import org.unidal.web.mvc.annotation.ModuleMeta;
public enum SystemPage implements Page {
ALARM("alarm", "alarm", "Alarm", "Alarm", true),
ALARM("alarm", "alarm", "Alarm", "Alarm", false),
LOGIN("login", "login", "Login", "Login", false),
CONFIG("config", "config", "Config", "Config", true),
CONFIG("config", "config", "Config", "Config", false),
PLUGIN("plugin", "plugin", "Plugin", "Plugin", true);
......
package com.dianping.cat.system.config;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.dal.jdbc.DalNotFoundException;
import org.unidal.helper.Files;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.Cat;
import com.dianping.cat.core.config.Config;
import com.dianping.cat.core.config.ConfigDao;
import com.dianping.cat.core.config.ConfigEntity;
import com.dianping.cat.home.alert.type.entity.AlertType;
import com.dianping.cat.home.alert.type.transform.DefaultSaxParser;
public class AlertTypeManager implements Initializable {
@Inject
private ConfigDao m_configDao;
private int m_configId;
private AlertType m_config;
private static final String CONFIG_NAME = "alertType";
public AlertType getAlertType() {
return m_config;
}
@Override
public void initialize() throws InitializationException {
try {
Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
String content = config.getContent();
m_configId = config.getId();
m_config = DefaultSaxParser.parse(content);
} catch (DalNotFoundException e) {
try {
String content = Files.forIO().readFrom(
this.getClass().getResourceAsStream("/config/default-alert-type.xml"), "utf-8");
Config config = m_configDao.createLocal();
config.setName(CONFIG_NAME);
config.setContent(content);
m_configDao.insert(config);
m_configId = config.getId();
m_config = DefaultSaxParser.parse(content);
} catch (Exception ex) {
Cat.logError(ex);
}
} catch (Exception e) {
Cat.logError(e);
}
if (m_config == null) {
m_config = new AlertType();
}
}
public boolean insert(String xml) {
try {
m_config = DefaultSaxParser.parse(xml);
return storeConfig();
} catch (Exception e) {
Cat.logError(e);
return false;
}
}
private boolean storeConfig() {
synchronized (this) {
try {
Config config = m_configDao.createLocal();
config.setId(m_configId);
config.setKeyId(m_configId);
config.setName(CONFIG_NAME);
config.setContent(m_config.toString());
m_configDao.updateByPK(config, ConfigEntity.UPDATESET_FULL);
} catch (Exception e) {
Cat.logError(e);
return false;
}
}
return true;
}
}
......@@ -69,6 +69,8 @@ public enum Action implements org.unidal.web.mvc.Action {
ALERT_DEFAULT_RECEIVERS("alertDefaultReceivers"),
ALERT_TYPE("alertTypes"),
EXCEPTION("exception"),
EXCEPTION_THRESHOLD_UPDATE("exceptionThresholdUpdate"),
......@@ -94,9 +96,9 @@ public enum Action implements org.unidal.web.mvc.Action {
METRIC_GROUP_CONFIG_UPDATE("metricGroupConfigUpdate"),
NET_GRAPH_CONFIG_UPDATE("netGraphConfigUpdate"),
APP_CONFIG_UPDATE("appConfigUpdate");
private String m_name;
public static Action getByName(String name, Action defaultAction) {
......
......@@ -47,6 +47,7 @@ import com.dianping.cat.report.service.ReportService;
import com.dianping.cat.report.view.DomainNavManager;
import com.dianping.cat.system.SystemPage;
import com.dianping.cat.system.config.AlertConfigManager;
import com.dianping.cat.system.config.AlertTypeManager;
import com.dianping.cat.system.config.BugConfigManager;
import com.dianping.cat.system.config.BusinessRuleConfigManager;
import com.dianping.cat.system.config.DomainGroupConfigManager;
......@@ -114,6 +115,9 @@ public class Handler implements PageHandler<Context> {
@Inject
private NetGraphConfigManager m_netGraphConfigManager;
@Inject
private AlertTypeManager m_alertTypeManager;
private void deleteAggregationRule(Payload payload) {
m_aggreationConfigManager.deleteAggregationRule(payload.getPattern());
}
......@@ -387,6 +391,16 @@ public class Handler implements PageHandler<Context> {
}
model.setContent(m_alertConfigManager.getAlertConfig().toString());
break;
case ALERT_TYPE:
String alertTypes = payload.getContent();
if (!StringUtils.isEmpty(alertTypes)) {
model.setOpState(m_alertTypeManager.insert(alertTypes));
} else {
model.setOpState(true);
}
model.setContent(m_alertTypeManager.getAlertType().toString());
break;
case EXCEPTION:
loadExceptionConfig(model);
break;
......
......@@ -43,6 +43,8 @@ public enum JspFile {
ALERT_DEFAULT_RECEIVERS("/jsp/system/defaultReceiver/alertDefaultReceivers.jsp"),
ALERT_TYPE("/jsp/system/alert/types.jsp"),
EXCEPTION_THRESHOLD("/jsp/system/exception/exceptionThreshold.jsp"),
EXCEPTION("/jsp/system/exception/exception.jsp"),
......@@ -58,9 +60,9 @@ public enum JspFile {
DOMAIN_GROUP_CONFIG_UPDATE("/jsp/system/domainGroup/domainGroupConfig.jsp"),
METRIC_GROUP_CONFIG_UPDATE("/jsp/system/metricGroup/metricGroupConfig.jsp"),
NET_GRAPH_CONFIG_UPDATE("/jsp/system/netGraphConfig/netGraphConfig.jsp"),
APP_CONFIG_UPDATE("/jsp/system/appConfig/appConfig.jsp");
private String m_path;
......
......@@ -82,6 +82,8 @@ public class JspViewer extends BaseJspViewer<SystemPage, Action, Context, Model>
return JspFile.SYSTEM_RULE_CONFIG_UPDATE.getPath();
case ALERT_DEFAULT_RECEIVERS:
return JspFile.ALERT_DEFAULT_RECEIVERS.getPath();
case ALERT_TYPE:
return JspFile.ALERT_TYPE.getPath();
// Excepton Config
case EXCEPTION:
case EXCEPTION_THRESHOLD_UPDATE_SUBMIT:
......@@ -109,7 +111,7 @@ public class JspViewer extends BaseJspViewer<SystemPage, Action, Context, Model>
case APP_CONFIG_UPDATE:
return JspFile.APP_CONFIG_UPDATE.getPath();
}
throw new RuntimeException("Unknown action: " + action);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<model>
<entity name="alert-type" root="true">
<entity-ref name="category" type="list" names="categories" />
</entity>
<entity name="category">
<attribute name="id" value-type="String" />
<entity-ref name="domain" type="list" names="domains" />
</entity>
<entity name="domain">
<attribute name="id" value-type="String" />
<entity-ref name="type" type="list" names="types" />
</entity>
<entity name="type">
<attribute name="id" value-type="String" />
<attribute name="sendSms" value-type="boolean" />
<attribute name="sendMail" value-type="boolean" />
<attribute name="sendWeixin" value-type="boolean" />
</entity>
</model>
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<file path="alert-type-codegen.xml" />
<file path="alert-type-model.xml" />
</manifest>
<?xml version="1.0" encoding="UTF-8"?>
<model model-package="com.dianping.cat.home.alert.type"
enable-sax-parser="true" enable-xml-parser="true" enable-xml-builder="true">
<entity name="alert-type" root="true">
<entity-ref name="category" type="map" names="categories"
method-find-or-create='true' />
</entity>
<entity name="category">
<attribute name="id" value-type="String" key="true" />
<entity-ref name="domain" type="map" names="domains"
method-find-or-create='true' />
</entity>
<entity name="domain">
<attribute name="id" value-type="String" key="true" />
<entity-ref name="type" type="map" names="types"
method-find-or-create='true' />
</entity>
<entity name="type">
<attribute name="id" value-type="String" key="true" />
<attribute name="sendSms" value-type="boolean" />
<attribute name="sendMail" value-type="boolean" />
<attribute name="sendWeixin" value-type="boolean" />
</entity>
</model>
......@@ -3873,6 +3873,9 @@
<requirement>
<role>com.dianping.cat.report.page.app.graph.AppGraphCreator</role>
</requirement>
<requirement>
<role>com.dianping.cat.report.page.PayloadNormalizer</role>
</requirement>
</requirements>
</component>
<component>
......@@ -4161,6 +4164,9 @@
<requirement>
<role>com.dianping.cat.system.config.NetGraphConfigManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.system.config.AlertTypeManager</role>
</requirement>
</requirements>
</component>
<component>
......@@ -4229,6 +4235,15 @@
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.system.config.AlertTypeManager</role>
<implementation>com.dianping.cat.system.config.AlertTypeManager</implementation>
<requirements>
<requirement>
<role>com.dianping.cat.core.config.ConfigDao</role>
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.system.page.plugin.Handler</role>
<implementation>com.dianping.cat.system.page.plugin.Handler</implementation>
......@@ -7624,6 +7639,9 @@
<requirement>
<role>com.dianping.cat.report.page.app.graph.AppGraphCreator</role>
</requirement>
<requirement>
<role>com.dianping.cat.report.page.PayloadNormalizer</role>
</requirement>
</requirements>
</component>
<component>
......@@ -7912,6 +7930,9 @@
<requirement>
<role>com.dianping.cat.system.config.NetGraphConfigManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.system.config.AlertTypeManager</role>
</requirement>
</requirements>
</component>
<component>
......@@ -7980,6 +8001,15 @@
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.system.config.AlertTypeManager</role>
<implementation>com.dianping.cat.system.config.AlertTypeManager</implementation>
<requirements>
<requirement>
<role>com.dianping.cat.core.config.ConfigDao</role>
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.system.page.plugin.Handler</role>
<implementation>com.dianping.cat.system.page.plugin.Handler</implementation>
......
......@@ -54,4 +54,7 @@
<model package="com.dianping.cat.home.alertsummary" name="alertsummary">
<sample-model>/Users/leon/Desktop/AlertSummary.xml</sample-model>
</model>
<model package="com.dianping.cat.home.alert.type" name="alert-type">
<sample-model>/Users/leon/Documents/GitRepo/cat/cat-home/src/test/resources/config/alert-type.xml</sample-model>
</model>
</wizard>
......@@ -26,7 +26,7 @@
<page name="dashboard" title="Dashboard" path="dashboard" standalone="false">
<description>Dashboard</description>
</page>
<page name="matrix" title="Matrix" path="matrix" view="/jsp/report/matrix/matrix.jsp">
<page name="matrix" title="Matrix" path="matrix" view="/jsp/report/matrix/matrix.jsp" standalone="false">
<description>Matrix</description>
</page>
<page name="cross" title="Cross" path="cross" view="/jsp/report/cross/cross.jsp">
......@@ -50,25 +50,25 @@
<page name="externalError" title="externalError" path="externalError" template="default">
<description>ExternalError</description>
</page>
<page name="statistics" title="Statistics" path="statistics" view="/jsp/report/bug/bug.jsp" template="default">
<page name="statistics" title="Statistics" path="statistics" view="/jsp/report/bug/bug.jsp" standalone="false" template="default">
<description>Statistics</description>
</page>
<page name="alteration" title="Change" path="alteration" template="default">
<page name="alteration" title="Change" path="alteration" standalone="false" template="default">
<description>Alteration</description>
</page>
<page name="monitor" title="Monitor" path="monitor" template="default">
<description>Monitor</description>
</page>
<page name="network" title="Network" path="network" template="default">
<page name="network" title="Network" path="network" standalone="false" template="default">
<description>Network</description>
</page>
<page name="userMonitor" title="Monitor" path="userMonitor" template="default">
<description>UserMonitor</description>
</page>
<page name="system" title="System" path="system" template="default">
<page name="system" title="System" path="system" standalone="false" template="default">
<description>System</description>
</page>
<page name="cdn" title="Cdn" path="cdn" template="default">
<page name="cdn" title="Cdn" path="cdn" standalone="false" template="default">
<description>Cdn</description>
</page>
<page name="app" title="App" path="app" template="default">
......@@ -76,13 +76,13 @@
</page>
</module>
<module name="system" path="s" default="false">
<page name="alarm" title="Alarm" default="true" path="alarm" view="/jsp/system/alarm/alarm.jsp">
<page name="alarm" title="Alarm" default="true" path="alarm" view="/jsp/system/alarm/alarm.jsp" standalone="false">
<description>Alarm</description>
</page>
<page name="login" title="Login" default="true" path="login" standalone="false">
<description>Login</description>
</page>
<page name="config" title="Config" path="config" view="/jsp/system/project/project.jsp">
<page name="config" title="Config" path="config" view="/jsp/system/project/project.jsp" standalone="false">
<description>Config</description>
</page>
<page name="plugin" title="Plugin" path="plugin" view="/jsp/system/plugin/plugin.jsp">
......
......@@ -69,7 +69,7 @@ function TabManager() {
var value = headers[i]["value"];
console.debug("\t" + name + " : " + value);
}
if(tabId <= 0) {
if(tabId <= 0) {
return;
}
......
<alert-type>
<category id="network">
<domain id="default">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="warning" sendSms="false" sendMail="true" sendWeixin="true" />
</domain>
</category>
<category id="exception">
<domain id="default">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="warning" sendSms="false" sendMail="true" sendWeixin="true" />
</domain>
</category>
<category id="business">
<domain id="default">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="warning" sendSms="false" sendMail="true" sendWeixin="true" />
</domain>
</category>
<category id="system">
<domain id="default">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="warning" sendSms="false" sendMail="true" sendWeixin="true" />
</domain>
</category>
</alert-type>
\ No newline at end of file
<app-config>
<config-item id="网络类型">
<item id="1" name="2G"></item>
<item id="2" name="3G"></item>
<item id="3" name="4G"></item>
<item id="1" name="WIFI"></item>
<item id="2" name="2G"></item>
<item id="3" name="3G"></item>
<item id="4" name="4G"></item>
</config-item>
<config-item id="运营商">
<item id="1" name="中国移动"></item>
......@@ -52,10 +53,6 @@
<item id="31" name="云南省"></item>
<item id="32" name="浙江省"></item>
</config-item>
<config-item id="渠道">
<item id="1" name="360"></item>
<item id="2" name="apple"></item>
</config-item>
<config-item id="连接类型">
<item id="1" name="长连接"></item>
<item id="2" name="短连接"></item>
......
......@@ -18,26 +18,18 @@
<res:useCss value='${res.css.local.tiny_css}' media="screen and (max-width: 1050px)" target="head-css" />
<res:useCss value='${res.css.local.large_css}' media="screen and (min-width: 1050px)" target="head-css" />
</head>
<body>
<div class="navbar navbar-inverse">
<div class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="/cat/r/home?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">CAT</a>
<a class="brand" style="padding-right:20px" href="/cat/r/home?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">CAT</a>
<div class="nav-collapse collapse">
<div class="nav pull-right">
<c:forEach var="page" items="${navBar.systemPages}">
<c:if test="${page.standalone}">
<li ${model.page.name == page.name ? 'class="active"' : ''}><a
href="${model.webapp}/${page.moduleName}/${page.path}">${page.title}</a></li>
</c:if>
<c:if
test="${not page.standalone and model.page.name == page.name}">
<li class="active"><a href="#">${page.title}</a></li>
</c:if>
</c:forEach>
<div class="nav pull-right">
<li id="loginInfo" ></li>
</div>
<ul class="nav">
<ul class="nav">
<c:forEach var="page" items="${navBar.visiblePages}">
<c:if test="${page.standalone}">
<li ${model.page.name == page.name ? 'class="active"' : ''}><a
......@@ -48,7 +40,23 @@
<li class="active"><a href="#">${page.title}</a></li>
</c:if>
</c:forEach>
</ul>
</ul>
<ul class="nav">
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Other<b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="nav-header">Report</li>
<li><a style="padding:3px 30px" href="/cat/r/matrix?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">matrix</a></li>
<li><a style="padding:3px 30px" href="/cat/r/network?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">network</a></li>
<li><a style="padding:3px 30px" href="/cat/r/cdn?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">cdn</a></li>
<li><a style="padding:3px 30px" href="/cat/r/system?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">system</a></li>
<li><a style="padding:3px 30px" href="/cat/r/change?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">change</a></li>
<li><a style="padding:3px 30px" href="/cat/r/statistics?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">statistics</a></li>
<li class="nav-header">System</li>
<li><a style="padding:3px 30px" href="/cat/s/alarm?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">alarm</a></li>
<li><a style="padding:3px 30px" href="/cat/s/config?domain=${model.domain}&ip=${model.ipAddress}&date=${model.date}&reportType=${payload.reportType}&op=${payload.action.name}">config</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
......
......@@ -194,10 +194,9 @@
<c:forEach var="item" items="${model.commands}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 返回码 <select id="code" style="width: 120px;"><option
value='0'>All</option>
</select> 返回码 <select id="code" style="width: 120px;"><option value=''>All</option>
</select> 网络类型 <select id="network" style="width: 80px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.networks}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
......@@ -206,29 +205,29 @@
</tr>
<tr>
<th align=left>版本 <select id="version" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.versions}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 连接类型 <select id="connectionType" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.connectionTypes}"
varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 平台 <select id="platform" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.platforms}"
varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 地区 <select id="city" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.cities}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 运营商 <select id="operator" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.operators}"
varStatus="status">
<option value='${item.id}'>${item.name}</option>
......@@ -256,9 +255,9 @@
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 返回码 <select id="code2" style="width: 120px;">
<option value='0'>All</option>
<option value=''>All</option>
</select> 网络类型 <select id="network2" style="width: 80px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.networks}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
......@@ -267,29 +266,29 @@
</tr>
<tr>
<th align=left>版本 <select id="version2" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.versions}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 连接类型 <select id="connectionType2" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.connectionTypes}"
varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 平台 <select id="platform2" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.platforms}"
varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 地区 <select id="city2" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.cities}" varStatus="status">
<option value='${item.id}'>${item.name}</option>
</c:forEach>
</select> 运营商 <select id="operator2" style="width: 100px;">
<option value='0'>All</option>
<option value=''>All</option>
<c:forEach var="item" items="${model.operators}"
varStatus="status">
<option value='${item.id}'>${item.name}</option>
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
$('#bug').addClass('active');
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
$('#alert').addClass('active');
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
$('#alert').addClass('active');
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
$('#heavy').addClass('active');
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
......
......@@ -9,7 +9,6 @@
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<script type="text/javascript">
$(document).ready(function() {
$('#summary').addClass('active');
......
......@@ -18,7 +18,6 @@
</style>
<a:body>
<res:useCss value='${res.css.local.table_css}' target="head-css" />
<res:useJs value="${res.js.local['bootstrap.min.js']}" target="head-js"/>
<div class="report">
<table class="header">
......
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="a" uri="/WEB-INF/app.tld"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="res" uri="http://www.unidal.org/webres"%>
<%@ taglib prefix="w" uri="http://www.unidal.org/web/core"%>
<a:body>
<res:useJs value="${res.js.local['jquery.validate.min.js']}"
target="head-js" />
<res:useJs value="${res.js.local['dependencyConfig.js']}"
target="head-js" />
<res:useJs value="${res.js.local['alarm_js']}" target="head-js" />
<res:useCss value="${res.css.local['select2.css']}" target="head-css" />
<res:useJs value="${res.js.local['select2.min.js']}" target="head-js" />
<div class="row-fluid">
<div class="span2">
<%@include file="../configTree.jsp"%>
</div>
<div class="span10">
<form name="alertTypes" id="form" method="post"
action="${model.pageUri}?op=alertTypes"
onsubmit="return validate_form(this)">
<h4 class="text-center text-error" id="state">&nbsp;</h4>
<h4 class="text-center text-error">告警类型</h4>
<table
class="table table-striped table-bordered table-condensed table-hover">
<tr>
<td><textarea name="content" style="width: auto" rows="20"
cols="150">${model.content}</textarea></td>
</tr>
<tr>
<td style="text-align: center"><input class='btn btn-primary'
type="submit" name="submit" id="submit" value="提交" /></td>
</tr>
</table>
</form>
</div>
</div>
</a:body>
<script type="text/javascript">
$(document).ready(function() {
$('#types').addClass('active');
var state = '${model.opState}';
if (state == 'Success') {
$('#state').html('操作成功');
} else {
$('#state').html('操作失败');
}
setInterval(function() {
$('#state').html('&nbsp;');
}, 3000);
});
</script>
\ No newline at end of file
......@@ -21,7 +21,8 @@
<li class='nav-header'><h4>系统监控配置</h4></li>
<li class="text-right" id="systemRuleConfigUpdate"><a href="?op=systemRuleConfigUpdate"><strong>系统告警配置</strong></a></li>
<li class='nav-header'><h4>系统默认配置</h4></li>
<li class="text-right" id="alertDefaultReceivers"><a href="?op=alertDefaultReceivers"><strong>默认告警配置</strong></a></li>
<li class="text-right" id="alertDefaultReceivers"><a href="?op=alertDefaultReceivers"><strong>默认告警配置</strong></a></li>
<li class="text-right" id="types"><a href="?op=alertTypes"><strong>告警类型设置</strong></a></li>
<li class="text-right" id="bugConfigUpdate"><a href="?op=bugConfigUpdate"><strong>异常类型配置</strong></a></li>
<li class="text-right" id="domainGroupConfigUpdate"><a href="?op=domainGroupConfigUpdate"><strong>机器分组配置</strong></a></li>
</ul>
......
<alert-type>
<category id="network">
<domain id="cat">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="warning" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
</domain>
<domain id="cat">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
</domain>
<domain id="cat">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
</domain>
</category>
<category id="exception">
<domain id="cat">
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
<type id="error" sendSms="true" sendMail="true" sendWeixin="true" />
</domain>
</category>
</alert-type>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册