Merge changes I42f4f24a,I7c06cb9a
* changes: Add sql/connection_pool/connections metric Add Histogram0..3 to track bytes sent
This commit is contained in:
commit
1eaa1c97d9
@ -20,6 +20,7 @@ import com.google.gerrit.metrics.Counter1;
|
|||||||
import com.google.gerrit.metrics.Counter2;
|
import com.google.gerrit.metrics.Counter2;
|
||||||
import com.google.gerrit.metrics.Description;
|
import com.google.gerrit.metrics.Description;
|
||||||
import com.google.gerrit.metrics.Field;
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.Histogram1;
|
||||||
import com.google.gerrit.metrics.MetricMaker;
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
import com.google.gerrit.metrics.Timer1;
|
import com.google.gerrit.metrics.Timer1;
|
||||||
import com.google.gerrit.metrics.Description.Units;
|
import com.google.gerrit.metrics.Description.Units;
|
||||||
@ -36,6 +37,7 @@ public class RestApiMetrics {
|
|||||||
final Counter1<String> count;
|
final Counter1<String> count;
|
||||||
final Counter2<String, Integer> errorCount;
|
final Counter2<String, Integer> errorCount;
|
||||||
final Timer1<String> serverLatency;
|
final Timer1<String> serverLatency;
|
||||||
|
final Histogram1<String> responseBytes;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RestApiMetrics(MetricMaker metrics) {
|
RestApiMetrics(MetricMaker metrics) {
|
||||||
@ -59,6 +61,13 @@ public class RestApiMetrics {
|
|||||||
.setCumulative()
|
.setCumulative()
|
||||||
.setUnit(Units.MILLISECONDS),
|
.setUnit(Units.MILLISECONDS),
|
||||||
view);
|
view);
|
||||||
|
|
||||||
|
responseBytes = metrics.newHistogram(
|
||||||
|
"http/server/rest_api/response_bytes",
|
||||||
|
new Description("Size of response on network (may be gzip compressed)")
|
||||||
|
.setCumulative()
|
||||||
|
.setUnit(Units.BYTES),
|
||||||
|
view);
|
||||||
}
|
}
|
||||||
|
|
||||||
String view(ViewData viewData) {
|
String view(ViewData viewData) {
|
||||||
|
@ -43,6 +43,7 @@ import com.google.common.collect.Maps;
|
|||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import com.google.common.io.CountingOutputStream;
|
||||||
import com.google.common.math.IntMath;
|
import com.google.common.math.IntMath;
|
||||||
import com.google.common.net.HttpHeaders;
|
import com.google.common.net.HttpHeaders;
|
||||||
import com.google.gerrit.audit.AuditService;
|
import com.google.gerrit.audit.AuditService;
|
||||||
@ -206,6 +207,7 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
res.setHeader("Content-Disposition", "attachment");
|
res.setHeader("Content-Disposition", "attachment");
|
||||||
res.setHeader("X-Content-Type-Options", "nosniff");
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
||||||
int status = SC_OK;
|
int status = SC_OK;
|
||||||
|
long responseBytes = -1;
|
||||||
Object result = null;
|
Object result = null;
|
||||||
Multimap<String, String> params = LinkedHashMultimap.create();
|
Multimap<String, String> params = LinkedHashMultimap.create();
|
||||||
Object inputRequestBody = null;
|
Object inputRequestBody = null;
|
||||||
@ -353,46 +355,47 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
if (result != Response.none()) {
|
if (result != Response.none()) {
|
||||||
result = Response.unwrap(result);
|
result = Response.unwrap(result);
|
||||||
if (result instanceof BinaryResult) {
|
if (result instanceof BinaryResult) {
|
||||||
replyBinaryResult(req, res, (BinaryResult) result);
|
responseBytes = replyBinaryResult(req, res, (BinaryResult) result);
|
||||||
} else {
|
} else {
|
||||||
replyJson(req, res, config, result);
|
responseBytes = replyJson(req, res, config, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (MalformedJsonException e) {
|
} catch (MalformedJsonException e) {
|
||||||
replyError(req, res, status = SC_BAD_REQUEST,
|
responseBytes = replyError(req, res, status = SC_BAD_REQUEST,
|
||||||
"Invalid " + JSON_TYPE + " in request", e);
|
"Invalid " + JSON_TYPE + " in request", e);
|
||||||
} catch (JsonParseException e) {
|
} catch (JsonParseException e) {
|
||||||
replyError(req, res, status = SC_BAD_REQUEST,
|
responseBytes = replyError(req, res, status = SC_BAD_REQUEST,
|
||||||
"Invalid " + JSON_TYPE + " in request", e);
|
"Invalid " + JSON_TYPE + " in request", e);
|
||||||
} catch (BadRequestException e) {
|
} catch (BadRequestException e) {
|
||||||
replyError(req, res, status = SC_BAD_REQUEST, messageOr(e, "Bad Request"),
|
responseBytes = replyError(req, res, status = SC_BAD_REQUEST,
|
||||||
e.caching(), e);
|
messageOr(e, "Bad Request"), e.caching(), e);
|
||||||
} catch (AuthException e) {
|
} catch (AuthException e) {
|
||||||
replyError(req, res, status = SC_FORBIDDEN, messageOr(e, "Forbidden"),
|
responseBytes = replyError(req, res, status = SC_FORBIDDEN,
|
||||||
e.caching(), e);
|
messageOr(e, "Forbidden"), e.caching(), e);
|
||||||
} catch (AmbiguousViewException e) {
|
} catch (AmbiguousViewException e) {
|
||||||
replyError(req, res, status = SC_NOT_FOUND, messageOr(e, "Ambiguous"), e);
|
responseBytes = replyError(req, res, status = SC_NOT_FOUND,
|
||||||
|
messageOr(e, "Ambiguous"), e);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
replyError(req, res, status = SC_NOT_FOUND, messageOr(e, "Not Found"),
|
responseBytes = replyError(req, res, status = SC_NOT_FOUND,
|
||||||
e.caching(), e);
|
messageOr(e, "Not Found"), e.caching(), e);
|
||||||
} catch (MethodNotAllowedException e) {
|
} catch (MethodNotAllowedException e) {
|
||||||
replyError(req, res, status = SC_METHOD_NOT_ALLOWED,
|
responseBytes = replyError(req, res, status = SC_METHOD_NOT_ALLOWED,
|
||||||
messageOr(e, "Method Not Allowed"), e.caching(), e);
|
messageOr(e, "Method Not Allowed"), e.caching(), e);
|
||||||
} catch (ResourceConflictException e) {
|
} catch (ResourceConflictException e) {
|
||||||
replyError(req, res, status = SC_CONFLICT, messageOr(e, "Conflict"),
|
responseBytes = replyError(req, res, status = SC_CONFLICT,
|
||||||
e.caching(), e);
|
messageOr(e, "Conflict"), e.caching(), e);
|
||||||
} catch (PreconditionFailedException e) {
|
} catch (PreconditionFailedException e) {
|
||||||
replyError(req, res, status = SC_PRECONDITION_FAILED,
|
responseBytes = replyError(req, res, status = SC_PRECONDITION_FAILED,
|
||||||
messageOr(e, "Precondition Failed"), e.caching(), e);
|
messageOr(e, "Precondition Failed"), e.caching(), e);
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
replyError(req, res, status = 422, messageOr(e, "Unprocessable Entity"),
|
responseBytes = replyError(req, res, status = 422,
|
||||||
e.caching(), e);
|
messageOr(e, "Unprocessable Entity"), e.caching(), e);
|
||||||
} catch (NotImplementedException e) {
|
} catch (NotImplementedException e) {
|
||||||
replyError(req, res, status = SC_NOT_IMPLEMENTED,
|
responseBytes = replyError(req, res, status = SC_NOT_IMPLEMENTED,
|
||||||
messageOr(e, "Not Implemented"), e);
|
messageOr(e, "Not Implemented"), e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
status = SC_INTERNAL_SERVER_ERROR;
|
status = SC_INTERNAL_SERVER_ERROR;
|
||||||
handleException(e, req, res);
|
responseBytes = handleException(e, req, res);
|
||||||
} finally {
|
} finally {
|
||||||
String metric = viewData != null && viewData.view != null
|
String metric = viewData != null && viewData.view != null
|
||||||
? globals.metrics.view(viewData)
|
? globals.metrics.view(viewData)
|
||||||
@ -401,6 +404,9 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
if (status >= SC_BAD_REQUEST) {
|
if (status >= SC_BAD_REQUEST) {
|
||||||
globals.metrics.errorCount.increment(metric, status);
|
globals.metrics.errorCount.increment(metric, status);
|
||||||
}
|
}
|
||||||
|
if (responseBytes != -1) {
|
||||||
|
globals.metrics.responseBytes.record(metric, responseBytes);
|
||||||
|
}
|
||||||
globals.metrics.serverLatency.record(
|
globals.metrics.serverLatency.record(
|
||||||
metric,
|
metric,
|
||||||
System.nanoTime() - startNanos,
|
System.nanoTime() - startNanos,
|
||||||
@ -667,7 +673,7 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
throw new InstantiationException("Cannot make " + type);
|
throw new InstantiationException("Cannot make " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void replyJson(@Nullable HttpServletRequest req,
|
public static long replyJson(@Nullable HttpServletRequest req,
|
||||||
HttpServletResponse res,
|
HttpServletResponse res,
|
||||||
Multimap<String, String> config,
|
Multimap<String, String> config,
|
||||||
Object result)
|
Object result)
|
||||||
@ -683,7 +689,7 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
w.write('\n');
|
w.write('\n');
|
||||||
w.flush();
|
w.flush();
|
||||||
replyBinaryResult(req, res, asBinaryResult(buf)
|
return replyBinaryResult(req, res, asBinaryResult(buf)
|
||||||
.setContentType(JSON_TYPE)
|
.setContentType(JSON_TYPE)
|
||||||
.setCharacterEncoding(UTF_8));
|
.setCharacterEncoding(UTF_8));
|
||||||
}
|
}
|
||||||
@ -752,7 +758,7 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
static void replyBinaryResult(
|
static long replyBinaryResult(
|
||||||
@Nullable HttpServletRequest req,
|
@Nullable HttpServletRequest req,
|
||||||
HttpServletResponse res,
|
HttpServletResponse res,
|
||||||
BinaryResult bin) throws IOException {
|
BinaryResult bin) throws IOException {
|
||||||
@ -783,10 +789,13 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req == null || !"HEAD".equals(req.getMethod())) {
|
if (req == null || !"HEAD".equals(req.getMethod())) {
|
||||||
try (OutputStream dst = res.getOutputStream()) {
|
try (CountingOutputStream dst =
|
||||||
|
new CountingOutputStream(res.getOutputStream())) {
|
||||||
bin.writeTo(dst);
|
bin.writeTo(dst);
|
||||||
|
return dst.getCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
} finally {
|
} finally {
|
||||||
appResult.close();
|
appResult.close();
|
||||||
}
|
}
|
||||||
@ -993,7 +1002,7 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
viewData.pluginName, viewData.view.getClass());
|
viewData.pluginName, viewData.view.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleException(Throwable err, HttpServletRequest req,
|
private static long handleException(Throwable err, HttpServletRequest req,
|
||||||
HttpServletResponse res) throws IOException {
|
HttpServletResponse res) throws IOException {
|
||||||
String uri = req.getRequestURI();
|
String uri = req.getRequestURI();
|
||||||
if (!Strings.isNullOrEmpty(req.getQueryString())) {
|
if (!Strings.isNullOrEmpty(req.getQueryString())) {
|
||||||
@ -1003,16 +1012,17 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
|
|
||||||
if (!res.isCommitted()) {
|
if (!res.isCommitted()) {
|
||||||
res.reset();
|
res.reset();
|
||||||
replyError(req, res, SC_INTERNAL_SERVER_ERROR, "Internal server error", err);
|
return replyError(req, res, SC_INTERNAL_SERVER_ERROR, "Internal server error", err);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void replyError(HttpServletRequest req, HttpServletResponse res,
|
public static long replyError(HttpServletRequest req, HttpServletResponse res,
|
||||||
int statusCode, String msg, @Nullable Throwable err) throws IOException {
|
int statusCode, String msg, @Nullable Throwable err) throws IOException {
|
||||||
replyError(req, res, statusCode, msg, CacheControl.NONE, err);
|
return replyError(req, res, statusCode, msg, CacheControl.NONE, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void replyError(HttpServletRequest req,
|
public static long replyError(HttpServletRequest req,
|
||||||
HttpServletResponse res, int statusCode, String msg,
|
HttpServletResponse res, int statusCode, String msg,
|
||||||
CacheControl c, @Nullable Throwable err) throws IOException {
|
CacheControl c, @Nullable Throwable err) throws IOException {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
@ -1020,18 +1030,18 @@ public class RestApiServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
configureCaching(req, res, null, null, c);
|
configureCaching(req, res, null, null, c);
|
||||||
res.setStatus(statusCode);
|
res.setStatus(statusCode);
|
||||||
replyText(req, res, msg);
|
return replyText(req, res, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replyText(@Nullable HttpServletRequest req,
|
static long replyText(@Nullable HttpServletRequest req,
|
||||||
HttpServletResponse res, String text) throws IOException {
|
HttpServletResponse res, String text) throws IOException {
|
||||||
if ((req == null || isGetOrHead(req)) && isMaybeHTML(text)) {
|
if ((req == null || isGetOrHead(req)) && isMaybeHTML(text)) {
|
||||||
replyJson(req, res, ImmutableMultimap.of("pp", "0"), new JsonPrimitive(text));
|
return replyJson(req, res, ImmutableMultimap.of("pp", "0"), new JsonPrimitive(text));
|
||||||
} else {
|
} else {
|
||||||
if (!text.endsWith("\n")) {
|
if (!text.endsWith("\n")) {
|
||||||
text += "\n";
|
text += "\n";
|
||||||
}
|
}
|
||||||
replyBinaryResult(req, res,
|
return replyBinaryResult(req, res,
|
||||||
BinaryResult.create(text).setContentType("text/plain"));
|
BinaryResult.create(text).setContentType("text/plain"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ public class Daemon extends SiteProgram {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
if (dbInjector == null) {
|
if (dbInjector == null) {
|
||||||
dbInjector = createDbInjector(MULTI_USER);
|
dbInjector = createDbInjector(true /* enableMetrics */, MULTI_USER);
|
||||||
}
|
}
|
||||||
cfgInjector = createCfgInjector();
|
cfgInjector = createCfgInjector();
|
||||||
config = cfgInjector.getInstance(
|
config = cfgInjector.getInstance(
|
||||||
@ -325,7 +325,6 @@ public class Daemon extends SiteProgram {
|
|||||||
private Injector createSysInjector() {
|
private Injector createSysInjector() {
|
||||||
final List<Module> modules = new ArrayList<>();
|
final List<Module> modules = new ArrayList<>();
|
||||||
modules.add(SchemaVersionCheck.module());
|
modules.add(SchemaVersionCheck.module());
|
||||||
modules.add(new DropWizardMetricMaker.ApiModule());
|
|
||||||
modules.add(new DropWizardMetricMaker.RestModule());
|
modules.add(new DropWizardMetricMaker.RestModule());
|
||||||
modules.add(new LogFileCompressor.Module());
|
modules.add(new LogFileCompressor.Module());
|
||||||
modules.add(new WorkQueue.Module());
|
modules.add(new WorkQueue.Module());
|
||||||
|
@ -20,8 +20,6 @@ import com.google.common.cache.Cache;
|
|||||||
import com.google.gerrit.extensions.config.FactoryModule;
|
import com.google.gerrit.extensions.config.FactoryModule;
|
||||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
import com.google.gerrit.metrics.DisabledMetricMaker;
|
|
||||||
import com.google.gerrit.metrics.MetricMaker;
|
|
||||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||||
import com.google.gerrit.rules.PrologModule;
|
import com.google.gerrit.rules.PrologModule;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
@ -91,7 +89,6 @@ public class BatchProgramModule extends FactoryModule {
|
|||||||
install(reviewDbModule);
|
install(reviewDbModule);
|
||||||
install(new DiffExecutorModule());
|
install(new DiffExecutorModule());
|
||||||
install(PatchListCacheImpl.module());
|
install(PatchListCacheImpl.module());
|
||||||
bind(MetricMaker.class).to(DisabledMetricMaker.class);
|
|
||||||
|
|
||||||
// Plugins are not loaded and we're just running through each change
|
// Plugins are not loaded and we're just running through each change
|
||||||
// once, so don't worry about cache removal.
|
// once, so don't worry about cache removal.
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.pgm.util;
|
package com.google.gerrit.pgm.util;
|
||||||
|
|
||||||
import com.google.gerrit.common.SiteLibraryLoaderUtil;
|
import com.google.gerrit.common.SiteLibraryLoaderUtil;
|
||||||
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.config.SitePaths;
|
import com.google.gerrit.server.config.SitePaths;
|
||||||
import com.google.gerrit.server.schema.DataSourceProvider;
|
import com.google.gerrit.server.schema.DataSourceProvider;
|
||||||
@ -37,9 +38,10 @@ public class SiteLibraryBasedDataSourceProvider extends DataSourceProvider {
|
|||||||
@Inject
|
@Inject
|
||||||
SiteLibraryBasedDataSourceProvider(SitePaths site,
|
SiteLibraryBasedDataSourceProvider(SitePaths site,
|
||||||
@GerritServerConfig Config cfg,
|
@GerritServerConfig Config cfg,
|
||||||
|
MetricMaker metrics,
|
||||||
DataSourceProvider.Context ctx,
|
DataSourceProvider.Context ctx,
|
||||||
DataSourceType dst) {
|
DataSourceType dst) {
|
||||||
super(cfg, ctx, dst);
|
super(cfg, metrics, ctx, dst);
|
||||||
libdir = site.lib_dir;
|
libdir = site.lib_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,9 @@ import com.google.common.collect.Lists;
|
|||||||
import com.google.gerrit.common.Die;
|
import com.google.gerrit.common.Die;
|
||||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||||
|
import com.google.gerrit.metrics.DisabledMetricMaker;
|
||||||
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
|
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
|
||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.config.GerritServerConfigModule;
|
import com.google.gerrit.server.config.GerritServerConfigModule;
|
||||||
import com.google.gerrit.server.config.SitePath;
|
import com.google.gerrit.server.config.SitePath;
|
||||||
@ -93,7 +96,13 @@ public abstract class SiteProgram extends AbstractProgram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return provides database connectivity and site path. */
|
/** @return provides database connectivity and site path. */
|
||||||
protected Injector createDbInjector(final DataSourceProvider.Context context) {
|
protected Injector createDbInjector(DataSourceProvider.Context context) {
|
||||||
|
return createDbInjector(false, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return provides database connectivity and site path. */
|
||||||
|
protected Injector createDbInjector(final boolean enableMetrics,
|
||||||
|
final DataSourceProvider.Context context) {
|
||||||
final Path sitePath = getSitePath();
|
final Path sitePath = getSitePath();
|
||||||
final List<Module> modules = new ArrayList<>();
|
final List<Module> modules = new ArrayList<>();
|
||||||
|
|
||||||
@ -107,6 +116,17 @@ public abstract class SiteProgram extends AbstractProgram {
|
|||||||
};
|
};
|
||||||
modules.add(sitePathModule);
|
modules.add(sitePathModule);
|
||||||
|
|
||||||
|
if (enableMetrics) {
|
||||||
|
modules.add(new DropWizardMetricMaker.ApiModule());
|
||||||
|
} else {
|
||||||
|
modules.add(new AbstractModule() {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(MetricMaker.class).to(DisabledMetricMaker.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
modules.add(new LifecycleModule() {
|
modules.add(new LifecycleModule() {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
@ -91,6 +91,41 @@ public class DisabledMetricMaker extends MetricMaker {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Histogram0 newHistogram(String name, Description desc) {
|
||||||
|
return new Histogram0() {
|
||||||
|
@Override public void record(long value) {}
|
||||||
|
@Override public void remove() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <F1> Histogram1<F1> newHistogram(String name, Description desc,
|
||||||
|
Field<F1> field1) {
|
||||||
|
return new Histogram1<F1>() {
|
||||||
|
@Override public void record(F1 field1, long value) {}
|
||||||
|
@Override public void remove() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <F1, F2> Histogram2<F1, F2> newHistogram(String name, Description desc,
|
||||||
|
Field<F1> field1, Field<F2> field2) {
|
||||||
|
return new Histogram2<F1, F2>() {
|
||||||
|
@Override public void record(F1 field1, F2 field2, long value) {}
|
||||||
|
@Override public void remove() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(String name,
|
||||||
|
Description desc, Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||||
|
return new Histogram3<F1, F2, F3>() {
|
||||||
|
@Override public void record(F1 field1, F2 field2, F3 field3, long value) {}
|
||||||
|
@Override public void remove() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <V> CallbackMetric0<V> newCallbackMetric(String name,
|
public <V> CallbackMetric0<V> newCallbackMetric(String name,
|
||||||
Class<V> valueClass, Description desc) {
|
Class<V> valueClass, Description desc) {
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures the statistical distribution of values in a stream of data.
|
||||||
|
* <p>
|
||||||
|
* Suitable uses are "response size in bytes", etc.
|
||||||
|
*/
|
||||||
|
public abstract class Histogram0 implements RegistrationHandle {
|
||||||
|
/** Record a sample of a specified amount. */
|
||||||
|
public abstract void record(long value);
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures the statistical distribution of values in a stream of data.
|
||||||
|
* <p>
|
||||||
|
* Suitable uses are "response size in bytes", etc.
|
||||||
|
*
|
||||||
|
* @param <F1> type of the field.
|
||||||
|
*/
|
||||||
|
public abstract class Histogram1<F1> implements RegistrationHandle {
|
||||||
|
/** Record a sample of a specified amount. */
|
||||||
|
public abstract void record(F1 field1, long value);
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures the statistical distribution of values in a stream of data.
|
||||||
|
* <p>
|
||||||
|
* Suitable uses are "response size in bytes", etc.
|
||||||
|
*
|
||||||
|
* @param <F1> type of the field.
|
||||||
|
* @param <F2> type of the field.
|
||||||
|
*/
|
||||||
|
public abstract class Histogram2<F1, F2> implements RegistrationHandle {
|
||||||
|
/** Record a sample of a specified amount. */
|
||||||
|
public abstract void record(F1 field1, F2 field2, long value);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures the statistical distribution of values in a stream of data.
|
||||||
|
* <p>
|
||||||
|
* Suitable uses are "response size in bytes", etc.
|
||||||
|
*
|
||||||
|
* @param <F1> type of the field.
|
||||||
|
* @param <F2> type of the field.
|
||||||
|
* @param <F3> type of the field.
|
||||||
|
*/
|
||||||
|
public abstract class Histogram3<F1, F2, F3> implements RegistrationHandle {
|
||||||
|
/** Record a sample of a specified amount. */
|
||||||
|
public abstract void record(F1 field1, F2 field2, F3 field3, long value);
|
||||||
|
}
|
@ -46,6 +46,18 @@ public abstract class MetricMaker {
|
|||||||
String name, Description desc,
|
String name, Description desc,
|
||||||
Field<F1> field1, Field<F2> field2, Field<F3> field3);
|
Field<F1> field1, Field<F2> field2, Field<F3> field3);
|
||||||
|
|
||||||
|
/** Metric statistical distribution of values. */
|
||||||
|
public abstract Histogram0 newHistogram(String name, Description desc);
|
||||||
|
public abstract <F1> Histogram1<F1> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1);
|
||||||
|
public abstract <F1, F2> Histogram2<F1, F2> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1, Field<F2> field2);
|
||||||
|
public abstract <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1, Field<F2> field2, Field<F3> field3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant value that does not change.
|
* Constant value that does not change.
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics.dropwizard;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.gerrit.metrics.Description;
|
||||||
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker.HistogramImpl;
|
||||||
|
|
||||||
|
import com.codahale.metrics.Metric;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/** Abstract histogram broken down into buckets by {@link Field} values. */
|
||||||
|
abstract class BucketedHistogram implements BucketedMetric {
|
||||||
|
private final DropWizardMetricMaker metrics;
|
||||||
|
private final String name;
|
||||||
|
private final Description.FieldOrdering ordering;
|
||||||
|
protected final Field<?>[] fields;
|
||||||
|
protected final HistogramImpl total;
|
||||||
|
private final Map<Object, HistogramImpl> cells;
|
||||||
|
|
||||||
|
BucketedHistogram(DropWizardMetricMaker metrics, String name,
|
||||||
|
Description desc, Field<?>... fields) {
|
||||||
|
this.metrics = metrics;
|
||||||
|
this.name = name;
|
||||||
|
this.ordering = desc.getFieldOrdering();
|
||||||
|
this.fields = fields;
|
||||||
|
this.total = metrics.newHistogramImpl(name + "_total");
|
||||||
|
this.cells = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void doRemove() {
|
||||||
|
for (HistogramImpl c : cells.values()) {
|
||||||
|
c.remove();
|
||||||
|
}
|
||||||
|
total.remove();
|
||||||
|
metrics.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
HistogramImpl forceCreate(Object f1, Object f2) {
|
||||||
|
return forceCreate(ImmutableList.of(f1, f2));
|
||||||
|
}
|
||||||
|
|
||||||
|
HistogramImpl forceCreate(Object f1, Object f2, Object f3) {
|
||||||
|
return forceCreate(ImmutableList.of(f1, f2, f3));
|
||||||
|
}
|
||||||
|
|
||||||
|
HistogramImpl forceCreate(Object key) {
|
||||||
|
HistogramImpl c = cells.get(key);
|
||||||
|
if (c != null) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (cells) {
|
||||||
|
c = cells.get(key);
|
||||||
|
if (c == null) {
|
||||||
|
c = metrics.newHistogramImpl(submetric(key));
|
||||||
|
cells.put(key, c);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String submetric(Object key) {
|
||||||
|
return DropWizardMetricMaker.name(ordering, name, name(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract String name(Object key);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Metric getTotal() {
|
||||||
|
return total.metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Field<?>[] getFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Object, Metric> getCells() {
|
||||||
|
return Maps.transformValues(
|
||||||
|
cells,
|
||||||
|
new Function<HistogramImpl, Metric> () {
|
||||||
|
@Override
|
||||||
|
public Metric apply(HistogramImpl in) {
|
||||||
|
return in.metric;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,10 @@ import com.google.gerrit.metrics.Counter3;
|
|||||||
import com.google.gerrit.metrics.Description;
|
import com.google.gerrit.metrics.Description;
|
||||||
import com.google.gerrit.metrics.Description.FieldOrdering;
|
import com.google.gerrit.metrics.Description.FieldOrdering;
|
||||||
import com.google.gerrit.metrics.Field;
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.Histogram0;
|
||||||
|
import com.google.gerrit.metrics.Histogram1;
|
||||||
|
import com.google.gerrit.metrics.Histogram2;
|
||||||
|
import com.google.gerrit.metrics.Histogram3;
|
||||||
import com.google.gerrit.metrics.MetricMaker;
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
import com.google.gerrit.metrics.Timer0;
|
import com.google.gerrit.metrics.Timer0;
|
||||||
import com.google.gerrit.metrics.Timer1;
|
import com.google.gerrit.metrics.Timer1;
|
||||||
@ -227,6 +231,56 @@ public class DropWizardMetricMaker extends MetricMaker {
|
|||||||
return new TimerImpl(name, registry.timer(name));
|
return new TimerImpl(name, registry.timer(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Histogram0 newHistogram(String name, Description desc) {
|
||||||
|
checkHistogramDescription(name, desc);
|
||||||
|
define(name, desc);
|
||||||
|
return newHistogramImpl(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized <F1> Histogram1<F1> newHistogram(String name,
|
||||||
|
Description desc, Field<F1> field1) {
|
||||||
|
checkHistogramDescription(name, desc);
|
||||||
|
HistogramImpl1<F1> m = new HistogramImpl1<>(this, name, desc, field1);
|
||||||
|
define(name, desc);
|
||||||
|
bucketed.put(name, m);
|
||||||
|
return m.histogram1();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized <F1, F2> Histogram2<F1, F2> newHistogram(String name,
|
||||||
|
Description desc, Field<F1> field1, Field<F2> field2) {
|
||||||
|
checkHistogramDescription(name, desc);
|
||||||
|
HistogramImplN m = new HistogramImplN(this, name, desc, field1, field2);
|
||||||
|
define(name, desc);
|
||||||
|
bucketed.put(name, m);
|
||||||
|
return m.histogram2();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||||
|
checkHistogramDescription(name, desc);
|
||||||
|
HistogramImplN m = new HistogramImplN(this, name, desc, field1, field2, field3);
|
||||||
|
define(name, desc);
|
||||||
|
bucketed.put(name, m);
|
||||||
|
return m.histogram3();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkHistogramDescription(String name, Description desc) {
|
||||||
|
checkMetricName(name);
|
||||||
|
checkArgument(!desc.isConstant(), "histogram must not be constant");
|
||||||
|
checkArgument(!desc.isGauge(), "histogram must not be a gauge");
|
||||||
|
checkArgument(!desc.isRate(), "histogram must not be a rate");
|
||||||
|
checkArgument(desc.isCumulative(), "histogram must be cumulative");
|
||||||
|
}
|
||||||
|
|
||||||
|
HistogramImpl newHistogramImpl(String name) {
|
||||||
|
return new HistogramImpl(name, registry.histogram(name));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <V> CallbackMetric0<V> newCallbackMetric(
|
public <V> CallbackMetric0<V> newCallbackMetric(
|
||||||
String name, Class<V> valueClass, Description desc) {
|
String name, Class<V> valueClass, Description desc) {
|
||||||
@ -348,4 +402,25 @@ public class DropWizardMetricMaker extends MetricMaker {
|
|||||||
registry.remove(name);
|
registry.remove(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HistogramImpl extends Histogram0 {
|
||||||
|
private final String name;
|
||||||
|
final com.codahale.metrics.Histogram metric;
|
||||||
|
|
||||||
|
private HistogramImpl(String name, com.codahale.metrics.Histogram metric) {
|
||||||
|
this.name = name;
|
||||||
|
this.metric = metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void record(long value) {
|
||||||
|
metric.update(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
descriptions.remove(name);
|
||||||
|
registry.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics.dropwizard;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.gerrit.metrics.Description;
|
||||||
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.Histogram1;
|
||||||
|
|
||||||
|
/** Optimized version of {@link BucketedHistogram} for single dimension. */
|
||||||
|
class HistogramImpl1<F1> extends BucketedHistogram implements BucketedMetric {
|
||||||
|
HistogramImpl1(DropWizardMetricMaker metrics, String name,
|
||||||
|
Description desc, Field<F1> field1) {
|
||||||
|
super(metrics, name, desc, field1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Histogram1<F1> histogram1() {
|
||||||
|
return new Histogram1<F1>() {
|
||||||
|
@Override
|
||||||
|
public void record(F1 field1, long value) {
|
||||||
|
total.record(value);
|
||||||
|
forceCreate(field1).record(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
doRemove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String name(Object field1) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Function<Object, String> fmt =
|
||||||
|
(Function<Object, String>) fields[0].formatter();
|
||||||
|
|
||||||
|
return fmt.apply(field1).replace('/', '-');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (C) 2015 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.metrics.dropwizard;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.gerrit.metrics.Description;
|
||||||
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.Histogram2;
|
||||||
|
import com.google.gerrit.metrics.Histogram3;
|
||||||
|
|
||||||
|
/** Generalized implementation of N-dimensional Histogram metrics. */
|
||||||
|
class HistogramImplN extends BucketedHistogram implements BucketedMetric {
|
||||||
|
HistogramImplN(DropWizardMetricMaker metrics, String name,
|
||||||
|
Description desc, Field<?>... fields) {
|
||||||
|
super(metrics, name, desc, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
<F1, F2> Histogram2<F1, F2> histogram2() {
|
||||||
|
return new Histogram2<F1, F2>() {
|
||||||
|
@Override
|
||||||
|
public void record(F1 field1, F2 field2, long value) {
|
||||||
|
total.record(value);
|
||||||
|
forceCreate(field1, field2).record(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
doRemove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
<F1, F2, F3> Histogram3<F1, F2, F3> histogram3() {
|
||||||
|
return new Histogram3<F1, F2, F3>() {
|
||||||
|
@Override
|
||||||
|
public void record(F1 field1, F2 field2, F3 field3, long value) {
|
||||||
|
total.record(value);
|
||||||
|
forceCreate(field1, field2, field3).record(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
doRemove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
String name(Object key) {
|
||||||
|
ImmutableList<Object> keyList = (ImmutableList<Object>) key;
|
||||||
|
String[] parts = new String[fields.length];
|
||||||
|
for (int i = 0; i < fields.length; i++) {
|
||||||
|
Function<Object, String> fmt =
|
||||||
|
(Function<Object, String>) fields[i].formatter();
|
||||||
|
|
||||||
|
parts[i] = fmt.apply(keyList.get(i)).replace('/', '-');
|
||||||
|
}
|
||||||
|
return Joiner.on('/').join(parts);
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import com.google.gerrit.metrics.Field;
|
|||||||
|
|
||||||
import com.codahale.metrics.Counter;
|
import com.codahale.metrics.Counter;
|
||||||
import com.codahale.metrics.Gauge;
|
import com.codahale.metrics.Gauge;
|
||||||
|
import com.codahale.metrics.Histogram;
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.Metric;
|
import com.codahale.metrics.Metric;
|
||||||
import com.codahale.metrics.Snapshot;
|
import com.codahale.metrics.Snapshot;
|
||||||
@ -56,7 +57,9 @@ class MetricJson {
|
|||||||
Double p99_9;
|
Double p99_9;
|
||||||
|
|
||||||
Double min;
|
Double min;
|
||||||
|
Double avg;
|
||||||
Double max;
|
Double max;
|
||||||
|
Double sum;
|
||||||
Double std_dev;
|
Double std_dev;
|
||||||
|
|
||||||
List<FieldJson> fields;
|
List<FieldJson> fields;
|
||||||
@ -123,6 +126,24 @@ class MetricJson {
|
|||||||
min = s.getMin() / div;
|
min = s.getMin() / div;
|
||||||
max = s.getMax() / div;
|
max = s.getMax() / div;
|
||||||
std_dev = s.getStdDev() / div;
|
std_dev = s.getStdDev() / div;
|
||||||
|
|
||||||
|
} else if (metric instanceof Histogram) {
|
||||||
|
Histogram m = (Histogram) metric;
|
||||||
|
Snapshot s = m.getSnapshot();
|
||||||
|
count = m.getCount();
|
||||||
|
|
||||||
|
p50 = s.getMedian();
|
||||||
|
p75 = s.get75thPercentile();
|
||||||
|
p95 = s.get95thPercentile();
|
||||||
|
p98 = s.get98thPercentile();
|
||||||
|
p99 = s.get99thPercentile();
|
||||||
|
p99_9 = s.get999thPercentile();
|
||||||
|
|
||||||
|
min = (double) s.getMin();
|
||||||
|
avg = (double) s.getMean();
|
||||||
|
max = (double) s.getMax();
|
||||||
|
sum = s.getMean() * m.getCount();
|
||||||
|
std_dev = s.getStdDev();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import com.google.gerrit.metrics.Counter1;
|
|||||||
import com.google.gerrit.metrics.Description;
|
import com.google.gerrit.metrics.Description;
|
||||||
import com.google.gerrit.metrics.Description.Units;
|
import com.google.gerrit.metrics.Description.Units;
|
||||||
import com.google.gerrit.metrics.Field;
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.Histogram1;
|
||||||
import com.google.gerrit.metrics.MetricMaker;
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
import com.google.gerrit.metrics.Timer1;
|
import com.google.gerrit.metrics.Timer1;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@ -39,6 +40,7 @@ public class UploadPackMetricsHook implements PostUploadHook {
|
|||||||
private final Timer1<Operation> counting;
|
private final Timer1<Operation> counting;
|
||||||
private final Timer1<Operation> compressing;
|
private final Timer1<Operation> compressing;
|
||||||
private final Timer1<Operation> writing;
|
private final Timer1<Operation> writing;
|
||||||
|
private final Histogram1<Operation> packBytes;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UploadPackMetricsHook(MetricMaker metricMaker) {
|
UploadPackMetricsHook(MetricMaker metricMaker) {
|
||||||
@ -70,6 +72,13 @@ public class UploadPackMetricsHook implements PostUploadHook {
|
|||||||
.setCumulative()
|
.setCumulative()
|
||||||
.setUnit(Units.MILLISECONDS),
|
.setUnit(Units.MILLISECONDS),
|
||||||
operation);
|
operation);
|
||||||
|
|
||||||
|
packBytes = metricMaker.newHistogram(
|
||||||
|
"git/upload-pack/pack_bytes",
|
||||||
|
new Description("Distribution of sizes of packs sent to clients")
|
||||||
|
.setCumulative()
|
||||||
|
.setUnit(Units.BYTES),
|
||||||
|
operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,5 +93,6 @@ public class UploadPackMetricsHook implements PostUploadHook {
|
|||||||
counting.record(op, stats.getTimeCounting(), MILLISECONDS);
|
counting.record(op, stats.getTimeCounting(), MILLISECONDS);
|
||||||
compressing.record(op, stats.getTimeCompressing(), MILLISECONDS);
|
compressing.record(op, stats.getTimeCompressing(), MILLISECONDS);
|
||||||
writing.record(op, stats.getTimeWriting(), MILLISECONDS);
|
writing.record(op, stats.getTimeWriting(), MILLISECONDS);
|
||||||
|
packBytes.record(op, stats.getTotalBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,10 @@ import com.google.gerrit.metrics.Counter2;
|
|||||||
import com.google.gerrit.metrics.Counter3;
|
import com.google.gerrit.metrics.Counter3;
|
||||||
import com.google.gerrit.metrics.Description;
|
import com.google.gerrit.metrics.Description;
|
||||||
import com.google.gerrit.metrics.Field;
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.Histogram0;
|
||||||
|
import com.google.gerrit.metrics.Histogram1;
|
||||||
|
import com.google.gerrit.metrics.Histogram2;
|
||||||
|
import com.google.gerrit.metrics.Histogram3;
|
||||||
import com.google.gerrit.metrics.MetricMaker;
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
import com.google.gerrit.metrics.Timer0;
|
import com.google.gerrit.metrics.Timer0;
|
||||||
import com.google.gerrit.metrics.Timer1;
|
import com.google.gerrit.metrics.Timer1;
|
||||||
@ -117,6 +121,41 @@ class PluginMetricMaker extends MetricMaker implements LifecycleListener {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Histogram0 newHistogram(String name, Description desc) {
|
||||||
|
Histogram0 m = root.newHistogram(prefix + name, desc);
|
||||||
|
cleanup.add(m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <F1> Histogram1<F1> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1) {
|
||||||
|
Histogram1<F1> m = root.newHistogram(prefix + name, desc, field1);
|
||||||
|
cleanup.add(m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <F1, F2> Histogram2<F1, F2> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1, Field<F2> field2) {
|
||||||
|
Histogram2<F1, F2> m = root.newHistogram(prefix + name, desc, field1, field2);
|
||||||
|
cleanup.add(m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <F1, F2, F3> Histogram3<F1, F2, F3> newHistogram(
|
||||||
|
String name, Description desc,
|
||||||
|
Field<F1> field1, Field<F2> field2, Field<F3> field3) {
|
||||||
|
Histogram3<F1, F2, F3> m =
|
||||||
|
root.newHistogram(prefix + name, desc, field1, field2, field3);
|
||||||
|
cleanup.add(m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <V> CallbackMetric0<V> newCallbackMetric(
|
public <V> CallbackMetric0<V> newCallbackMetric(
|
||||||
String name, Class<V> valueClass, Description desc) {
|
String name, Class<V> valueClass, Description desc) {
|
||||||
|
@ -20,6 +20,10 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||||
import com.google.gerrit.extensions.persistence.DataSourceInterceptor;
|
import com.google.gerrit.extensions.persistence.DataSourceInterceptor;
|
||||||
|
import com.google.gerrit.metrics.CallbackMetric1;
|
||||||
|
import com.google.gerrit.metrics.Description;
|
||||||
|
import com.google.gerrit.metrics.Field;
|
||||||
|
import com.google.gerrit.metrics.MetricMaker;
|
||||||
import com.google.gerrit.server.config.ConfigSection;
|
import com.google.gerrit.server.config.ConfigSection;
|
||||||
import com.google.gerrit.server.config.ConfigUtil;
|
import com.google.gerrit.server.config.ConfigUtil;
|
||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
@ -46,15 +50,18 @@ public class DataSourceProvider implements Provider<DataSource>,
|
|||||||
public static final int DEFAULT_POOL_LIMIT = 8;
|
public static final int DEFAULT_POOL_LIMIT = 8;
|
||||||
|
|
||||||
private final Config cfg;
|
private final Config cfg;
|
||||||
|
private final MetricMaker metrics;
|
||||||
private final Context ctx;
|
private final Context ctx;
|
||||||
private final DataSourceType dst;
|
private final DataSourceType dst;
|
||||||
private DataSource ds;
|
private DataSource ds;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DataSourceProvider(@GerritServerConfig Config cfg,
|
protected DataSourceProvider(@GerritServerConfig Config cfg,
|
||||||
|
MetricMaker metrics,
|
||||||
Context ctx,
|
Context ctx,
|
||||||
DataSourceType dst) {
|
DataSourceType dst) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
|
this.metrics = metrics;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.dst = dst;
|
this.dst = dst;
|
||||||
}
|
}
|
||||||
@ -126,6 +133,7 @@ public class DataSourceProvider implements Provider<DataSource>,
|
|||||||
ds.setMaxWait(ConfigUtil.getTimeUnit(cfg, "database", null,
|
ds.setMaxWait(ConfigUtil.getTimeUnit(cfg, "database", null,
|
||||||
"poolmaxwait", MILLISECONDS.convert(30, SECONDS), MILLISECONDS));
|
"poolmaxwait", MILLISECONDS.convert(30, SECONDS), MILLISECONDS));
|
||||||
ds.setInitialSize(ds.getMinIdle());
|
ds.setInitialSize(ds.getMinIdle());
|
||||||
|
exportPoolMetrics(ds);
|
||||||
return intercept(interceptor, ds);
|
return intercept(interceptor, ds);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -148,6 +156,25 @@ public class DataSourceProvider implements Provider<DataSource>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void exportPoolMetrics(final BasicDataSource pool) {
|
||||||
|
final CallbackMetric1<Boolean, Integer> cnt = metrics.newCallbackMetric(
|
||||||
|
"sql/connection_pool/connections",
|
||||||
|
Integer.class,
|
||||||
|
new Description("SQL database connections")
|
||||||
|
.setGauge()
|
||||||
|
.setUnit("connections"),
|
||||||
|
Field.ofBoolean("active"));
|
||||||
|
metrics.newTrigger(cnt, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (pool) {
|
||||||
|
cnt.set(true, pool.getNumActive());
|
||||||
|
cnt.set(false, pool.getNumIdle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private DataSource intercept(String interceptor, DataSource ds) {
|
private DataSource intercept(String interceptor, DataSource ds) {
|
||||||
if (interceptor == null) {
|
if (interceptor == null) {
|
||||||
return ds;
|
return ds;
|
||||||
|
@ -261,6 +261,7 @@ public class WebAppInitializer extends GuiceServletContextListener
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
modules.add(new DatabaseModule());
|
modules.add(new DatabaseModule());
|
||||||
|
modules.add(new DropWizardMetricMaker.ApiModule());
|
||||||
return Guice.createInjector(PRODUCTION, modules);
|
return Guice.createInjector(PRODUCTION, modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +290,6 @@ public class WebAppInitializer extends GuiceServletContextListener
|
|||||||
|
|
||||||
private Injector createSysInjector() {
|
private Injector createSysInjector() {
|
||||||
final List<Module> modules = new ArrayList<>();
|
final List<Module> modules = new ArrayList<>();
|
||||||
modules.add(new DropWizardMetricMaker.ApiModule());
|
|
||||||
modules.add(new DropWizardMetricMaker.RestModule());
|
modules.add(new DropWizardMetricMaker.RestModule());
|
||||||
modules.add(new WorkQueue.Module());
|
modules.add(new WorkQueue.Module());
|
||||||
modules.add(new ChangeHookRunner.Module());
|
modules.add(new ChangeHookRunner.Module());
|
||||||
|
Loading…
Reference in New Issue
Block a user