Plugin API: Add datasource interception extension point
This change extends the plugin API to support monitoring of Gerrit's
SQL activity by providing the extension point to create a DataSource
proxy to intercept execution of SQL statements.
To activate SQL monitoring the following must be done:
Add the interceptor class to gerrit.config:
dataSourceInterceptorClass = javamelody.JavamelodyInterceptor
Implement the interface DataSourceInterceptor:
public class JavamelodyInterceptor implements DataSourceInterceptor {
@Override
public DataSource intercept(String name, DataSource dataSource) {
return JdbcWrapper.SINGLETON.createDataSourceProxy(name, dataSource);
}
}
Put the jar containing the interceptor into $gerrit_site/lib directory.
Working example of this concept can be found in javamelody-plugin.
Change-Id: I5f0b5ffe072394eae77e3b1735a76dceff4bdc42
This commit is contained in:
committed by
Shawn Pearce
parent
55bc67720e
commit
38a6f6cc2d
@@ -1221,6 +1221,13 @@ Default is `30 seconds`.
|
||||
This setting only applies if
|
||||
<<database.connectionPool,database.connectionPool>> is true.
|
||||
|
||||
[[database.dataSourceInterceptorClass]]database.dataSourceInterceptorClass::
|
||||
|
||||
Class that implements DataSourceInterceptor interface to monitor SQL activity.
|
||||
This class must have default constructor and be available on Gerrit's bootstrap
|
||||
classpath, e. g. in `$gerrit_site/lib` directory. Example implementation of
|
||||
SQL monitoring can be found in javamelody-plugin.
|
||||
|
||||
[[download]]
|
||||
=== Section download
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2014 The Android Open Source Project
|
||||
//
|
||||
// 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.google.gerrit.extensions.persistence;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
public interface DataSourceInterceptor {
|
||||
DataSource intercept(String name, DataSource dataSource);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||
import com.google.gerrit.extensions.persistence.DataSourceInterceptor;
|
||||
import com.google.gerrit.server.config.ConfigSection;
|
||||
import com.google.gerrit.server.config.ConfigUtil;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
@@ -32,6 +33,8 @@ import com.google.inject.Singleton;
|
||||
import org.apache.commons.dbcp.BasicDataSource;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -102,6 +105,7 @@ public class DataSourceProvider implements Provider<DataSource>,
|
||||
|
||||
String username = dbs.optional("username");
|
||||
String password = dbs.optional("password");
|
||||
String interceptor = dbs.optional("dataSourceInterceptorClass");
|
||||
|
||||
boolean usePool;
|
||||
if (context == Context.SINGLE_USER) {
|
||||
@@ -126,7 +130,7 @@ public class DataSourceProvider implements Provider<DataSource>,
|
||||
ds.setMaxWait(ConfigUtil.getTimeUnit(cfg, "database", null,
|
||||
"poolmaxwait", MILLISECONDS.convert(30, SECONDS), MILLISECONDS));
|
||||
ds.setInitialSize(ds.getMinIdle());
|
||||
return ds;
|
||||
return intercept(interceptor, ds);
|
||||
|
||||
} else {
|
||||
// Don't use the connection pool.
|
||||
@@ -141,10 +145,26 @@ public class DataSourceProvider implements Provider<DataSource>,
|
||||
if (password != null) {
|
||||
p.setProperty("password", password);
|
||||
}
|
||||
return new SimpleDataSource(p);
|
||||
return intercept(interceptor, new SimpleDataSource(p));
|
||||
} catch (SQLException se) {
|
||||
throw new ProvisionException("Database unavailable", se);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DataSource intercept(String interceptor, DataSource ds) {
|
||||
if (interceptor == null) {
|
||||
return ds;
|
||||
}
|
||||
try {
|
||||
Constructor<?> c = Class.forName(interceptor).getConstructor();
|
||||
DataSourceInterceptor datasourceInterceptor =
|
||||
(DataSourceInterceptor) c.newInstance();
|
||||
return datasourceInterceptor.intercept("reviewDb", ds);
|
||||
} catch (ClassNotFoundException | SecurityException | NoSuchMethodException
|
||||
| IllegalArgumentException | InstantiationException
|
||||
| IllegalAccessException | InvocationTargetException e) {
|
||||
throw new ProvisionException("Cannot intercept datasource", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user