提交 d1a24df0 编写于 作者: T terrymanu

refactor Metrics

上级 3a06b9d2
......@@ -18,12 +18,12 @@
package com.dangdang.ddframe.rdb.sharding.spring.cases.namespace;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import com.dangdang.ddframe.rdb.sharding.metrics.ThreadLocalObjectContainer;
import com.dangdang.ddframe.rdb.sharding.spring.AbstractShardingBothDataBasesAndTablesSpringDBUnitTest;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import java.sql.Connection;
import java.sql.SQLException;
import static org.junit.Assert.assertNotNull;
......@@ -31,11 +31,9 @@ import static org.junit.Assert.assertNotNull;
public final class WithNamespaceAlgorithmClassAndPropsTest extends AbstractShardingBothDataBasesAndTablesSpringDBUnitTest {
@Test
public void testMetricsContextWhenEnable() throws NoSuchFieldException {
public void testMetricsContextWhenEnable() throws SQLException {
try (Connection connection = getShardingDataSource().getConnection()) {
assertNotNull(ThreadLocalObjectContainer.getItem(MetricsContext.class));
} catch (Exception ex) {
ex.printStackTrace();
assertNotNull(MetricsContext.start("name"));
}
}
}
......@@ -18,7 +18,6 @@
package com.dangdang.ddframe.rdb.sharding.api;
import com.dangdang.ddframe.rdb.sharding.api.props.ShardingProperties;
import com.dangdang.ddframe.rdb.sharding.api.props.ShardingPropertiesConstant;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import com.dangdang.ddframe.rdb.sharding.executor.ExecutorEngine;
......@@ -26,7 +25,6 @@ import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingConnection;
import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingContext;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractDataSourceAdapter;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import com.dangdang.ddframe.rdb.sharding.metrics.ThreadLocalObjectContainer;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteEngine;
import com.google.common.base.Preconditions;
......@@ -41,9 +39,9 @@ import java.util.Properties;
*/
public class ShardingDataSource extends AbstractDataSourceAdapter {
private final ThreadLocalObjectContainer threadLocalObjectContainer = new ThreadLocalObjectContainer();
private final ShardingContext shardingContext;
private final ShardingContext context;
private final ShardingProperties shardingProperties;
public ShardingDataSource(final ShardingRule shardingRule) {
this(shardingRule, new Properties());
......@@ -52,29 +50,20 @@ public class ShardingDataSource extends AbstractDataSourceAdapter {
public ShardingDataSource(final ShardingRule shardingRule, final Properties props) {
Preconditions.checkNotNull(shardingRule);
Preconditions.checkNotNull(props);
ShardingProperties shardingProperties = new ShardingProperties(props);
initThreadLocalObjectContainer(shardingProperties);
shardingProperties = new ShardingProperties(props);
DatabaseType type;
try {
type = DatabaseType.valueFrom(ShardingConnection.getDatabaseMetaDataFromDataSource(shardingRule.getDataSourceRule().getDataSources()).getDatabaseProductName());
} catch (final SQLException ex) {
throw new ShardingJdbcException("Can not get database product name", ex);
}
context = new ShardingContext(shardingRule, new SQLRouteEngine(shardingRule, type), new ExecutorEngine(shardingProperties));
}
private void initThreadLocalObjectContainer(final ShardingProperties shardingProperties) {
if (shardingProperties.getValue(ShardingPropertiesConstant.METRICS_ENABLE)) {
long period = shardingProperties.getValue(ShardingPropertiesConstant.METRICS_MILLISECONDS_PERIOD);
String loggerName = shardingProperties.getValue(ShardingPropertiesConstant.METRICS_LOGGER_NAME);
threadLocalObjectContainer.initItem(new MetricsContext(period, loggerName));
}
shardingContext = new ShardingContext(shardingRule, new SQLRouteEngine(shardingRule, type), new ExecutorEngine(shardingProperties));
}
@Override
public ShardingConnection getConnection() throws SQLException {
threadLocalObjectContainer.build();
return new ShardingConnection(context);
MetricsContext.init(shardingProperties);
return new ShardingConnection(shardingContext);
}
@Override
......
......@@ -33,6 +33,7 @@ import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractConnectionAdapter;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
......@@ -64,7 +65,7 @@ public final class ShardingConnection extends AbstractConnectionAdapter {
if (connectionMap.containsKey(dataSourceName)) {
return connectionMap.get(dataSourceName);
}
Context metricsContext = MetricsContext.start("ShardingConnection-getConnection", dataSourceName);
Context metricsContext = MetricsContext.start(Joiner.on("-").join("ShardingConnection-getConnection", dataSourceName));
Connection connection = shardingContext.getShardingRule().getDataSourceRule().getDataSource(dataSourceName).getConnection();
MetricsContext.stop(metricsContext);
replayMethodsInvocation(connection);
......
......@@ -24,7 +24,7 @@ import java.sql.SQLWarning;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationConnection;
import com.dangdang.ddframe.rdb.sharding.metrics.ThreadLocalObjectContainer;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
/**
* 数据库连接适配类.
......@@ -80,7 +80,7 @@ public abstract class AbstractConnectionAdapter extends AbstractUnsupportedOpera
each.close();
}
closed = true;
ThreadLocalObjectContainer.clear();
MetricsContext.clear();
}
@Override
......
......@@ -4,9 +4,9 @@
* 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.
......@@ -17,46 +17,64 @@
package com.dangdang.ddframe.rdb.sharding.metrics;
import java.util.concurrent.TimeUnit;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Slf4jReporter;
import com.codahale.metrics.Slf4jReporter.LoggingLevel;
import com.codahale.metrics.Timer.Context;
import com.google.common.base.Joiner;
import com.codahale.metrics.Timer;
import com.dangdang.ddframe.rdb.sharding.api.props.ShardingProperties;
import com.dangdang.ddframe.rdb.sharding.api.props.ShardingPropertiesConstant;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
/**
* 度量工具上下文.
* 度量上下文持有者.
*
* <p>
* 多个ShardingDataSource使用静态度量上下文会造成数据污染, 所以将度量上下文对象绑定到ThreadLocal中.
* </p>
*
* @author gaohongtao
* @author zhangliang
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class MetricsContext {
private final MetricRegistry metricRegistry;
private static final ThreadLocal<MetricRegistry> HOLDER = new ThreadLocal<>();
public MetricsContext(final long period, final String loggerName) {
metricRegistry = new MetricRegistry();
Slf4jReporter reporter = Slf4jReporter.forRegistry(metricRegistry)
/**
* 初始化度量上下文持有者.
*
* @param shardingProperties Sharding-JDBC的配置属性
*/
public static void init(final ShardingProperties shardingProperties) {
HOLDER.remove();
boolean metricsEnabled = shardingProperties.getValue(ShardingPropertiesConstant.METRICS_ENABLE);
if (!metricsEnabled) {
return;
}
long period = shardingProperties.getValue(ShardingPropertiesConstant.METRICS_MILLISECONDS_PERIOD);
String loggerName = shardingProperties.getValue(ShardingPropertiesConstant.METRICS_LOGGER_NAME);
MetricRegistry metricRegistry = new MetricRegistry();
Slf4jReporter.forRegistry(metricRegistry)
.outputTo(LoggerFactory.getLogger(loggerName))
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.withLoggingLevel(LoggingLevel.DEBUG)
.build();
reporter.start(period, TimeUnit.MILLISECONDS);
.withLoggingLevel(Slf4jReporter.LoggingLevel.DEBUG)
.build().start(period, TimeUnit.MILLISECONDS);
HOLDER.set(metricRegistry);
}
/**
* 开始计时.
*
* @param name 度量目标名称
*
*
* @return 计时上下文
*/
public static Context start(final String... name) {
MetricsContext context = ThreadLocalObjectContainer.getItem(MetricsContext.class);
return null == context ? null : context.metricRegistry.timer(MetricRegistry.name(Joiner.on("-").join(name))).time();
public static Timer.Context start(final String name) {
return null == HOLDER.get() ? null : HOLDER.get().timer(MetricRegistry.name(name)).time();
}
/**
......@@ -64,9 +82,16 @@ public final class MetricsContext {
*
* @param context 计时上下文
*/
public static void stop(final Context context) {
public static void stop(final Timer.Context context) {
if (null != context) {
context.stop();
}
}
/**
* 清理数据.
*/
public static void clear() {
HOLDER.remove();
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.metrics;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal对象容器.
*
* <p>
* 多个ShardingDataSource使用静态对象会造成数据污染, 故使用该类来将这些对象绑定到ThreadLocal中.
* </p>
*
* @author gaohongtao
*/
public final class ThreadLocalObjectContainer {
private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL_CONTAINER = new ThreadLocal<>();
private final Map<String, Object> data = new HashMap<>();
/**
* 向容器内添加初始对象.
*
* @param item 受容器管理的对象
*/
public void initItem(final Object item) {
data.put(item.getClass().getName(), item);
}
/**
* 开始使用容器.
* 在本线程开始执行前要调用此方法设置线程对象状态.
*
*/
public void build() {
THREAD_LOCAL_CONTAINER.remove();
THREAD_LOCAL_CONTAINER.set(data);
}
/**
* 清理线程中的数据.
*
*/
public static void clear() {
THREAD_LOCAL_CONTAINER.remove();
}
/**
* 获取线程中对象.
*
* @param clazz 对象类型
* @return 对象
*/
public static <T> T getItem(final Class<T> clazz) {
return (T) (null == THREAD_LOCAL_CONTAINER.get() ? null : THREAD_LOCAL_CONTAINER.get().get(clazz.getName()));
}
}
......@@ -23,7 +23,6 @@ import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
MetricsContextTest.class,
ThreadLocalObjectContainerTest.class
})
public class AllMetricsTest {
}
......@@ -17,29 +17,61 @@
package com.dangdang.ddframe.rdb.sharding.metrics;
import com.dangdang.ddframe.rdb.sharding.api.props.ShardingProperties;
import com.dangdang.ddframe.rdb.sharding.api.props.ShardingPropertiesConstant;
import org.junit.After;
import org.junit.Test;
import com.codahale.metrics.Timer.Context;
import java.util.Properties;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public final class MetricsContextTest {
@After
public void tearDown(){
MetricsContext.clear();
}
@Test
public void assertStartWhenMetricsDisable() {
initDisabledMetrics();
assertNull(MetricsContext.start("name"));
}
@Test
public void assertStartWhenMetricsEnable() {
initEnabledMetrics();
assertNotNull(MetricsContext.start("name"));
}
@Test
public void assertStopWhenMetricsDisable() {
initDisabledMetrics();
MetricsContext.stop(null);
}
@Test
public void assertMetricsContextEnable() {
run(true);
public void assertStopWhenMetricsEnable() {
initEnabledMetrics();
MetricsContext.stop(MetricsContext.start("name"));
}
@Test
public void assertMetricsContextDisable() {
run(false);
}
private void run(final boolean enable) {
if(enable){
ThreadLocalObjectContainer container = new ThreadLocalObjectContainer();
container.initItem(new MetricsContext(1000000L, "example"));
container.build();
}
Context context = MetricsContext.start("example");
MetricsContext.stop(context);
public void assertClear() {
initEnabledMetrics();
MetricsContext.clear();
assertNull(MetricsContext.start("name"));
}
private void initDisabledMetrics() {
MetricsContext.init(new ShardingProperties(new Properties()));
}
private void initEnabledMetrics() {
Properties props = new Properties();
props.setProperty(ShardingPropertiesConstant.METRICS_ENABLE.getKey(), Boolean.TRUE.toString());
MetricsContext.init(new ShardingProperties(props));
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.metrics;
import org.junit.After;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
public final class ThreadLocalObjectContainerTest {
private final ThreadLocalObjectContainer threadLocalObjectContainer = new ThreadLocalObjectContainer();
@Test
public void assertGetItemWithoutBuild() {
threadLocalObjectContainer.initItem("init");
assertNull(ThreadLocalObjectContainer.getItem(String.class));
}
@Test
public void assertGetItemWithBuild() {
threadLocalObjectContainer.initItem("init");
threadLocalObjectContainer.build();
assertThat(ThreadLocalObjectContainer.getItem(String.class), is("init"));
}
@After
public void clear(){
ThreadLocalObjectContainer.clear();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册