mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-17 18:51:10 +01:00
Core metrics (#1586)
Expose metrics for http requests and executor services.
This commit is contained in:
@@ -26,8 +26,11 @@ package sonia.scm.admin;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.metrics.Metrics;
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
import sonia.scm.version.Version;
|
||||
|
||||
@@ -46,7 +49,7 @@ public class ReleaseFeedParser {
|
||||
public static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReleaseFeedParser.class);
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
static final String SPAN_KIND = "Release Feed";
|
||||
|
||||
@@ -56,14 +59,24 @@ public class ReleaseFeedParser {
|
||||
private Future<Optional<UpdateInfo>> updateInfoFuture;
|
||||
|
||||
@Inject
|
||||
public ReleaseFeedParser(AdvancedHttpClient client) {
|
||||
this(client, DEFAULT_TIMEOUT_IN_MILLIS);
|
||||
public ReleaseFeedParser(AdvancedHttpClient client, MeterRegistry registry) {
|
||||
this(client, registry, DEFAULT_TIMEOUT_IN_MILLIS);
|
||||
}
|
||||
|
||||
public ReleaseFeedParser(AdvancedHttpClient client, long timeoutInMillis) {
|
||||
public ReleaseFeedParser(AdvancedHttpClient client, MeterRegistry registry, long timeoutInMillis) {
|
||||
this.client = client;
|
||||
this.timeoutInMillis = timeoutInMillis;
|
||||
this.executorService = Executors.newSingleThreadExecutor();
|
||||
this.executorService = createExecutorService(registry);
|
||||
}
|
||||
|
||||
private ExecutorService createExecutorService(MeterRegistry registry) {
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor(
|
||||
new ThreadFactoryBuilder()
|
||||
.setNameFormat("ReleaseFeedParser")
|
||||
.build()
|
||||
);
|
||||
Metrics.executor(registry, executor, "ReleaseFeedParser", "single");
|
||||
return executor;
|
||||
}
|
||||
|
||||
Optional<UpdateInfo> findLatestRelease(String url) {
|
||||
|
||||
@@ -27,6 +27,7 @@ package sonia.scm.api.v2.resources;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -43,6 +44,7 @@ import sonia.scm.importexport.ExportFileExtensionResolver;
|
||||
import sonia.scm.importexport.ExportService;
|
||||
import sonia.scm.importexport.FullScmRepositoryExporter;
|
||||
import sonia.scm.importexport.RepositoryImportExportEncryption;
|
||||
import sonia.scm.metrics.Metrics;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
@@ -104,7 +106,10 @@ public class RepositoryExportResource {
|
||||
RepositoryImportExportEncryption repositoryImportExportEncryption,
|
||||
ExportService exportService,
|
||||
RepositoryExportInformationToDtoMapper informationToDtoMapper,
|
||||
ExportFileExtensionResolver fileExtensionResolver, ResourceLinks resourceLinks) {
|
||||
ExportFileExtensionResolver fileExtensionResolver,
|
||||
ResourceLinks resourceLinks,
|
||||
MeterRegistry registry
|
||||
) {
|
||||
this.manager = manager;
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.fullScmRepositoryExporter = fullScmRepositoryExporter;
|
||||
@@ -113,7 +118,7 @@ public class RepositoryExportResource {
|
||||
this.informationToDtoMapper = informationToDtoMapper;
|
||||
this.fileExtensionResolver = fileExtensionResolver;
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.repositoryExportHandler = this.createExportHandlerPool();
|
||||
this.repositoryExportHandler = this.createExportHandlerPool(registry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,12 +523,14 @@ public class RepositoryExportResource {
|
||||
return Instant.now().toString().replace(":", "-").split("\\.")[0];
|
||||
}
|
||||
|
||||
private ExecutorService createExportHandlerPool() {
|
||||
return Executors.newCachedThreadPool(
|
||||
private ExecutorService createExportHandlerPool(MeterRegistry registry) {
|
||||
ExecutorService executorService = Executors.newCachedThreadPool(
|
||||
new ThreadFactoryBuilder()
|
||||
.setNameFormat("RepositoryExportHandler-%d")
|
||||
.build()
|
||||
);
|
||||
Metrics.executor(registry, executorService, "RepositoryExport", "cached");
|
||||
return executorService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import io.micrometer.core.instrument.binder.http.DefaultHttpServletRequestTagsProvider;
|
||||
import io.micrometer.core.instrument.binder.http.HttpServletRequestTagsProvider;
|
||||
import sonia.scm.Priority;
|
||||
import sonia.scm.filter.Filters;
|
||||
import sonia.scm.filter.WebElement;
|
||||
import sonia.scm.web.filter.HttpFilter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@WebElement(Filters.PATTERN_ALL)
|
||||
@Priority(Filters.PRIORITY_PRE_BASEURL)
|
||||
public class HttpMetricsFilter extends HttpFilter {
|
||||
|
||||
static final String METRIC_DURATION = "scm.http.requests";
|
||||
|
||||
private final HttpServletRequestTagsProvider tagsProvider = new DefaultHttpServletRequestTagsProvider();
|
||||
|
||||
private final Provider<MeterRegistry> registryProvider;
|
||||
private final RequestCategoryDetector detector;
|
||||
|
||||
@Inject
|
||||
public HttpMetricsFilter(Provider<MeterRegistry> registryProvider, RequestCategoryDetector detector) {
|
||||
this.registryProvider = registryProvider;
|
||||
this.detector = detector;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
MeterRegistry registry = registryProvider.get();
|
||||
Timer.Sample sample = Timer.start(registry);
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
Tags tags = tags(request, response);
|
||||
sample.stop(timer(registry, tags));
|
||||
}
|
||||
}
|
||||
|
||||
private Timer timer(MeterRegistry registry, Tags tags) {
|
||||
return Timer.builder(METRIC_DURATION)
|
||||
.description("Duration of an http request")
|
||||
.tags(tags)
|
||||
.register(registry);
|
||||
}
|
||||
|
||||
private Tags tags(HttpServletRequest request, HttpServletResponse response) {
|
||||
Iterable<Tag> tags = tagsProvider.getTags(request, response);
|
||||
return Tags.concat(tags, "category", detector.detect(request).name());
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
|
||||
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
@@ -40,6 +42,8 @@ import java.util.Set;
|
||||
@Singleton
|
||||
public class MeterRegistryProvider implements Provider<MeterRegistry> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MeterRegistryProvider.class);
|
||||
|
||||
private final Set<MonitoringSystem> providerSet;
|
||||
|
||||
@Inject
|
||||
@@ -58,15 +62,20 @@ public class MeterRegistryProvider implements Provider<MeterRegistry> {
|
||||
|
||||
private MeterRegistry createRegistry() {
|
||||
if (providerSet.size() == 1) {
|
||||
return providerSet.iterator().next().getRegistry();
|
||||
MeterRegistry registry = providerSet.iterator().next().getRegistry();
|
||||
LOG.debug("create meter registry from single registration: {}", registry.getClass());
|
||||
return registry;
|
||||
}
|
||||
return createCompositeRegistry();
|
||||
}
|
||||
|
||||
private CompositeMeterRegistry createCompositeRegistry() {
|
||||
LOG.debug("create composite meter registry");
|
||||
CompositeMeterRegistry registry = new CompositeMeterRegistry();
|
||||
for (MonitoringSystem provider : providerSet) {
|
||||
registry.add(provider.getRegistry());
|
||||
MeterRegistry subRegistry = provider.getRegistry();
|
||||
LOG.debug("register {} as part of composite meter registry", subRegistry.getClass());
|
||||
registry.add(subRegistry);
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.metrics;
|
||||
|
||||
|
||||
public enum RequestCategory {
|
||||
|
||||
UI, API, PROTOCOL, STATIC, UNKNOWN
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.metrics;
|
||||
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.web.UserAgent;
|
||||
import sonia.scm.web.UserAgentParser;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public final class RequestCategoryDetector {
|
||||
|
||||
private final UserAgentParser userAgentParser;
|
||||
|
||||
@Inject
|
||||
public RequestCategoryDetector(UserAgentParser userAgentParser) {
|
||||
this.userAgentParser = userAgentParser;
|
||||
}
|
||||
|
||||
public RequestCategory detect(HttpServletRequest request) {
|
||||
String uri = HttpUtil.getStrippedURI(request);
|
||||
if (isStatic(uri)) {
|
||||
return RequestCategory.STATIC;
|
||||
} else if (HttpUtil.isWUIRequest(request)) {
|
||||
return RequestCategory.UI;
|
||||
} else if (uri.startsWith("/api/")) {
|
||||
return RequestCategory.API;
|
||||
} else if (uri.startsWith("/repo/") && isScmClient(request)) {
|
||||
return RequestCategory.PROTOCOL;
|
||||
}
|
||||
return RequestCategory.UNKNOWN;
|
||||
}
|
||||
|
||||
private boolean isStatic(String uri) {
|
||||
return uri.startsWith("/assets")
|
||||
|| uri.endsWith(".js")
|
||||
|| uri.endsWith(".css")
|
||||
|| uri.endsWith(".jpg")
|
||||
|| uri.endsWith(".jpeg")
|
||||
|| uri.endsWith(".png")
|
||||
|| uri.endsWith(".gif")
|
||||
|| uri.endsWith(".svg")
|
||||
|| uri.endsWith(".html");
|
||||
}
|
||||
|
||||
private boolean isScmClient(HttpServletRequest request) {
|
||||
UserAgent agent = userAgentParser.parse(request);
|
||||
return agent != null && agent.isScmClient();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,10 +26,8 @@ package sonia.scm.repository;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.apache.shiro.concurrent.SubjectAwareExecutorService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ConfigurationException;
|
||||
@@ -56,9 +54,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -75,10 +70,7 @@ import static sonia.scm.NotFoundException.notFound;
|
||||
@Singleton
|
||||
public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
||||
|
||||
private static final String THREAD_NAME = "Hook-%s";
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(DefaultRepositoryManager.class);
|
||||
private final ExecutorService executorService;
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultRepositoryManager.class);
|
||||
private final Map<String, RepositoryHandler> handlerMap;
|
||||
private final KeyGenerator keyGenerator;
|
||||
private final RepositoryDAO repositoryDAO;
|
||||
@@ -94,12 +86,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
||||
this.repositoryDAO = repositoryDAO;
|
||||
this.namespaceStrategyProvider = namespaceStrategyProvider;
|
||||
|
||||
ThreadFactory factory = new ThreadFactoryBuilder()
|
||||
.setNameFormat(THREAD_NAME).build();
|
||||
this.executorService = new SubjectAwareExecutorService(
|
||||
Executors.newCachedThreadPool(factory)
|
||||
);
|
||||
|
||||
handlerMap = new HashMap<>();
|
||||
types = new HashSet<>();
|
||||
|
||||
@@ -109,11 +95,8 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
||||
managerDaoAdapter = new ManagerDaoAdapter<>(repositoryDAO);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
executorService.shutdown();
|
||||
|
||||
for (RepositoryHandler handler : handlerMap.values()) {
|
||||
IOUtil.close(handler);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import sonia.scm.metrics.Metrics;
|
||||
import sonia.scm.repository.spi.SyncAsyncExecutor;
|
||||
import sonia.scm.repository.spi.SyncAsyncExecutorProvider;
|
||||
|
||||
@@ -48,8 +51,19 @@ public class DefaultSyncAsyncExecutorProvider implements SyncAsyncExecutorProvid
|
||||
private final int defaultMaxAsyncAbortSeconds;
|
||||
|
||||
@Inject
|
||||
public DefaultSyncAsyncExecutorProvider() {
|
||||
this(Executors.newFixedThreadPool(getProperty(NUMBER_OF_THREADS_PROPERTY, DEFAULT_NUMBER_OF_THREADS)));
|
||||
public DefaultSyncAsyncExecutorProvider(MeterRegistry registry) {
|
||||
this(createExecutorService(registry, getProperty(NUMBER_OF_THREADS_PROPERTY, DEFAULT_NUMBER_OF_THREADS)));
|
||||
}
|
||||
|
||||
private static ExecutorService createExecutorService(MeterRegistry registry, int fixed) {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(
|
||||
fixed,
|
||||
new ThreadFactoryBuilder()
|
||||
.setNameFormat("SyncAsyncExecutorProvider-%d")
|
||||
.build()
|
||||
);
|
||||
Metrics.executor(registry, executorService, "SyncAsyncExecutorProvider", "fixed");
|
||||
return executorService;
|
||||
}
|
||||
|
||||
public DefaultSyncAsyncExecutorProvider(ExecutorService executor) {
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.schedule;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.metrics.Metrics;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@@ -44,14 +46,16 @@ public class CronScheduler implements Scheduler {
|
||||
private final CronThreadFactory threadFactory;
|
||||
|
||||
@Inject
|
||||
public CronScheduler(CronTaskFactory taskFactory) {
|
||||
public CronScheduler(CronTaskFactory taskFactory, MeterRegistry registry) {
|
||||
this.taskFactory = taskFactory;
|
||||
this.threadFactory = new CronThreadFactory();
|
||||
this.executorService = createExecutor();
|
||||
this.executorService = createExecutor(registry);
|
||||
}
|
||||
|
||||
private ScheduledExecutorService createExecutor() {
|
||||
return Executors.newScheduledThreadPool(2, threadFactory);
|
||||
private ScheduledExecutorService createExecutor(MeterRegistry registry) {
|
||||
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2, threadFactory);
|
||||
Metrics.executor(registry, executor, "Cron", "scheduled");
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.template;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
@@ -32,16 +32,19 @@ import com.google.common.base.Throwables;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.google.inject.Inject;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.Default;
|
||||
import sonia.scm.metrics.Metrics;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
@@ -61,37 +64,43 @@ public class MustacheTemplateEngine implements TemplateEngine
|
||||
@Inject(optional = true) PluginLoader pluginLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to implement optional injection for the MeterRegistry.
|
||||
* @see <a href="https://github.com/google/guice/wiki/FrequentlyAskedQuestions#how-can-i-inject-optional-parameters-into-a-constructor">Optional Injection</a>
|
||||
*/
|
||||
static class MeterRegistryHolder {
|
||||
@Inject(optional = true) MeterRegistry registry;
|
||||
}
|
||||
|
||||
/** Field description */
|
||||
public static final TemplateType TYPE = new TemplateType("mustache",
|
||||
"Mustache", "mustache");
|
||||
|
||||
/** Field description */
|
||||
private static final String THREAD_NAME = "Mustache-%s";
|
||||
|
||||
/**
|
||||
* the logger for MustacheTemplateEngine
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(MustacheTemplateEngine.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* @param pluginLoaderHolder
|
||||
*/
|
||||
@Inject
|
||||
public MustacheTemplateEngine(@Default ServletContext context, PluginLoaderHolder pluginLoaderHolder)
|
||||
public MustacheTemplateEngine(@Default ServletContext context, PluginLoaderHolder pluginLoaderHolder, MeterRegistryHolder registryHolder)
|
||||
{
|
||||
factory = new ServletMustacheFactory(context, createClassLoader(pluginLoaderHolder.pluginLoader));
|
||||
factory.setExecutorService(createExecutorService(registryHolder.registry));
|
||||
}
|
||||
|
||||
ThreadFactory threadFactory =
|
||||
new ThreadFactoryBuilder().setNameFormat(THREAD_NAME).build();
|
||||
private static ExecutorService createExecutorService(@Nullable MeterRegistry registry) {
|
||||
ExecutorService executorService = Executors.newCachedThreadPool(
|
||||
new ThreadFactoryBuilder()
|
||||
.setNameFormat("MustacheTemplateEngine-%d")
|
||||
.build()
|
||||
);
|
||||
|
||||
factory.setExecutorService(Executors.newCachedThreadPool(threadFactory));
|
||||
if (registry != null) {
|
||||
Metrics.executor(registry, executorService,"MustacheTemplateEngine", "cached" );
|
||||
}
|
||||
|
||||
return executorService;
|
||||
}
|
||||
|
||||
private ClassLoader createClassLoader(PluginLoader pluginLoader) {
|
||||
|
||||
@@ -21,23 +21,24 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.web.cgi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.metrics.Metrics;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -50,13 +51,19 @@ public class DefaultCGIExecutorFactory implements CGIExecutorFactory, AutoClosea
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public DefaultCGIExecutorFactory()
|
||||
{
|
||||
//J-
|
||||
this.executor = Executors.newCachedThreadPool(
|
||||
new ThreadFactoryBuilder().setNameFormat("cgi-pool-%d").build()
|
||||
@Inject
|
||||
public DefaultCGIExecutorFactory(MeterRegistry registry) {
|
||||
this.executor = createExecutor(registry);
|
||||
}
|
||||
|
||||
private ExecutorService createExecutor(MeterRegistry registry) {
|
||||
ExecutorService executorService = Executors.newCachedThreadPool(
|
||||
new ThreadFactoryBuilder()
|
||||
.setNameFormat("cgi-pool-%d")
|
||||
.build()
|
||||
);
|
||||
//J+
|
||||
Metrics.executor(registry, executorService, "CGI", "cached");
|
||||
return executorService;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user