diff --git a/core/src/main/java/org/mapfish/print/cli/Main.java b/core/src/main/java/org/mapfish/print/cli/Main.java index c12502eac2..5ed5b29fff 100644 --- a/core/src/main/java/org/mapfish/print/cli/Main.java +++ b/core/src/main/java/org/mapfish/print/cli/Main.java @@ -3,7 +3,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.util.StatusPrinter; +import ch.qos.logback.core.util.StatusPrinter2; import com.google.common.annotations.VisibleForTesting; import com.sampullara.cli.Args; import java.io.File; @@ -58,7 +58,6 @@ private Main() { * Main method. * * @param args the cli arguments - * @throws Exception */ public static void main(final String[] args) throws Exception { runMain(args); @@ -69,7 +68,6 @@ public static void main(final String[] args) throws Exception { * Runs the print. * * @param args the cli arguments - * @throws Exception */ @VisibleForTesting public static void runMain(final String[] args) throws Exception { @@ -133,17 +131,20 @@ private static void configureLogs(final String verbose) { case LOGLEVEL_INFO: logfile = classLoader.getResource("shell-info-log.xml"); break; - case LOGLEVEL_DEFAULT: - logfile = classLoader.getResource("shell-default-log.xml"); - break; case LOGLEVEL_VERBOSE: logfile = classLoader.getResource("shell-verbose-log.xml"); break; + case LOGLEVEL_DEFAULT: default: logfile = classLoader.getResource("shell-default-log.xml"); break; } + LoggerContext loggerContext = getLoggerContext(logfile); + new StatusPrinter2().printInCaseOfErrorsOrWarnings(loggerContext); + } + + private static LoggerContext getLoggerContext(final URL logfile) { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); try { @@ -156,15 +157,15 @@ private static void configureLogs(final String verbose) { } catch (JoranException je) { // StatusPrinter will handle this } - StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext); + return loggerContext; } /** - * Instead of calling system.exit an exception will be thrown. This is useful for testing so a - * test won't shutdown jvm. + * Instead of calling System.exit() an exception will be thrown. This is useful for testing so a + * test won't shut down the jvm. * - * @param exceptionOnFailure if true then an exception will be thrown instead of system.exit being - * called. + * @param exceptionOnFailure if true then an exception will be thrown instead of System.exit() + * being called. */ @VisibleForTesting static void setExceptionOnFailure(final boolean exceptionOnFailure) { @@ -197,7 +198,7 @@ private void run(final CliDefinition cli) throws Exception { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Request Data: \n{}", jsonSpec.getInternalObj().toString(2)); } - this.mapPrinter.print(new HashMap(), jsonSpec, outFile); + this.mapPrinter.print(new HashMap<>(), jsonSpec, outFile); } } } diff --git a/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java b/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java index 58ab3d3c0e..d8f1827fbc 100644 --- a/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java +++ b/core/src/main/java/org/mapfish/print/http/HttpRequestFetcher.java @@ -189,7 +189,10 @@ public OutputStream getBody() { @Nonnull public ClientHttpResponse execute() { assert this.future != null; - Timer timerWait = HttpRequestFetcher.this.registry.timer(buildMetricName(".waitDownloader")); + Timer timerWait = + HttpRequestFetcher.this.registry.timer( + MetricRegistry.name( + HttpRequestFetcher.class.getSimpleName(), "TimeWaitingDownloader")); try (Timer.Context ignored = timerWait.time()) { this.future.join(); } @@ -204,16 +207,15 @@ public ClientHttpResponse execute() { return result; } - private String buildMetricName(final String suffix) { - return HttpRequestFetcher.class.getName() + suffix; - } - @Override public Void call() throws Exception { return context.mdcContextEx( () -> { final String baseMetricName = - buildMetricName(".read." + StatsUtils.quotePart(getURI().getHost())); + MetricRegistry.name( + HttpRequestFetcher.class.getSimpleName(), + "read", + StatsUtils.quotePart(getURI().getHost())); Timer timerDownload = HttpRequestFetcher.this.registry.timer(baseMetricName); try (Timer.Context ignored = timerDownload.time()) { try { @@ -221,8 +223,9 @@ public Void call() throws Exception { this.response = new CachedClientHttpResponse(this.originalRequest.execute()); } catch (IOException | RuntimeException e) { LOGGER.error("Request failed {}", this.originalRequest.getURI(), e); + String errorCounter = MetricRegistry.name(baseMetricName, "error"); + HttpRequestFetcher.this.registry.counter(errorCounter).inc(); this.response = new ErrorResponseClientHttpResponse(e); - HttpRequestFetcher.this.registry.counter(baseMetricName + ".error").inc(); } } return null; diff --git a/core/src/main/java/org/mapfish/print/map/image/AbstractSingleImageLayer.java b/core/src/main/java/org/mapfish/print/map/image/AbstractSingleImageLayer.java index 419916e4d6..2082c70b15 100644 --- a/core/src/main/java/org/mapfish/print/map/image/AbstractSingleImageLayer.java +++ b/core/src/main/java/org/mapfish/print/map/image/AbstractSingleImageLayer.java @@ -67,7 +67,7 @@ protected AbstractSingleImageLayer( final ExecutorService executorService, final StyleSupplier styleSupplier, final AbstractLayerParams params, - final MetricRegistry registry, + @Nonnull final MetricRegistry registry, final Configuration configuration) { super(executorService, params); this.styleSupplier = styleSupplier; @@ -168,14 +168,15 @@ protected BufferedImage fetchImage( return fetchImageFromHttpResponse(request, httpResponse, transformer, baseMetricName); } catch (RuntimeException e) { - this.registry.counter(baseMetricName + ".error").inc(); + this.registry.counter(MetricRegistry.name(baseMetricName, "error")).inc(); throw e; } } } private String getBaseMetricName(@Nonnull final ClientHttpRequest request) { - return getClass().getName() + ".read." + StatsUtils.quotePart(request.getURI().getHost()); + return MetricRegistry.name( + getClass().getSimpleName(), "read", StatsUtils.quotePart(request.getURI().getHost())); } private static String getInvalidResponseBody( @@ -215,7 +216,7 @@ private boolean isResponseStatusCodeValid( if (stringBody != null) { message += "\nContent:\n" + stringBody; } - this.registry.counter(baseMetricName + ".error").inc(); + this.registry.counter(MetricRegistry.name(baseMetricName, "error")).inc(); if (getFailOnError()) { throw new RuntimeException(message); } else { @@ -237,7 +238,7 @@ private boolean isResponseBodyValid( request.getURI(), contentType.get(0), responseBody); - this.registry.counter(baseMetricName + ".error").inc(); + this.registry.counter(MetricRegistry.name(baseMetricName, "error")).inc(); if (getFailOnError()) { throw new RuntimeException("Wrong content-type : " + contentType.get(0)); } else { @@ -256,7 +257,7 @@ private BufferedImage fetchImageFromHttpResponse( final BufferedImage image = ImageIO.read(httpResponse.getBody()); if (image == null) { LOGGER.warn("Cannot read image from {}", request.getURI()); - this.registry.counter(baseMetricName + ".error").inc(); + this.registry.counter(MetricRegistry.name(baseMetricName, "error")).inc(); if (getFailOnError()) { throw new RuntimeException("Cannot read image from " + request.getURI()); } diff --git a/core/src/main/java/org/mapfish/print/map/image/wms/WmsLayer.java b/core/src/main/java/org/mapfish/print/map/image/wms/WmsLayer.java index 119bc52214..070303bb16 100644 --- a/core/src/main/java/org/mapfish/print/map/image/wms/WmsLayer.java +++ b/core/src/main/java/org/mapfish/print/map/image/wms/WmsLayer.java @@ -35,7 +35,7 @@ public final class WmsLayer extends AbstractSingleImageLayer { * @param registry the metrics registry. * @param configuration the configuration. */ - protected WmsLayer( + WmsLayer( @Nonnull final ExecutorService executorService, @Nonnull final StyleSupplier styleSupplier, @Nonnull final WmsLayerParam params, diff --git a/core/src/main/java/org/mapfish/print/metrics/HealthCheckingRegistry.java b/core/src/main/java/org/mapfish/print/metrics/HealthCheckingRegistry.java index 4e1f4f3b59..468a177362 100644 --- a/core/src/main/java/org/mapfish/print/metrics/HealthCheckingRegistry.java +++ b/core/src/main/java/org/mapfish/print/metrics/HealthCheckingRegistry.java @@ -4,10 +4,12 @@ import org.springframework.beans.factory.annotation.Autowired; public class HealthCheckingRegistry extends com.codahale.metrics.health.HealthCheckRegistry { - @Autowired private ApplicationStatus applicationStatus; + @Autowired private JobQueueHealthCheck jobQueueHealthCheck; + @Autowired private UnhealthyCountersHealthCheck unhealthyCountersHealthCheck; @PostConstruct public void registerHealthCheck() { - register("application", applicationStatus); + register("jobQueueStatus", jobQueueHealthCheck); + register("unhealthyCountersStatus", unhealthyCountersHealthCheck); } } diff --git a/core/src/main/java/org/mapfish/print/metrics/ApplicationStatus.java b/core/src/main/java/org/mapfish/print/metrics/JobQueueHealthCheck.java similarity index 94% rename from core/src/main/java/org/mapfish/print/metrics/ApplicationStatus.java rename to core/src/main/java/org/mapfish/print/metrics/JobQueueHealthCheck.java index 96b214924f..9fe5f9e489 100644 --- a/core/src/main/java/org/mapfish/print/metrics/ApplicationStatus.java +++ b/core/src/main/java/org/mapfish/print/metrics/JobQueueHealthCheck.java @@ -9,7 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -class ApplicationStatus extends HealthCheck { +public class JobQueueHealthCheck extends HealthCheck { @Value("${healthStatus.expectedMaxTime.sinceLastPrint.InSeconds}") private int secondsInFloatingWindow; @@ -34,7 +34,7 @@ protected Result check() throws Exception { String health = ". Number of print jobs waiting is " + waitingJobsCount; if (jobManager.getLastExecutedJobTimestamp() == null) { - return Result.unhealthy("No print job was ever processed by this server" + health); + return Result.unhealthy("This server never processed a print job" + health); } else if (hasThisServerPrintedRecently()) { // WIP (See issue https://github.com/mapfish/mapfish-print/issues/3393) if (waitingJobsCount > maxNbrPrintJobQueued) { diff --git a/core/src/main/java/org/mapfish/print/metrics/UnhealthyCountersHealthCheck.java b/core/src/main/java/org/mapfish/print/metrics/UnhealthyCountersHealthCheck.java new file mode 100644 index 0000000000..d273767b4d --- /dev/null +++ b/core/src/main/java/org/mapfish/print/metrics/UnhealthyCountersHealthCheck.java @@ -0,0 +1,49 @@ +package org.mapfish.print.metrics; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheck; +import java.util.HashSet; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; + +public class UnhealthyCountersHealthCheck extends HealthCheck { + @Autowired private MetricRegistry metricRegistry; + + private final Set unhealthyCounters = new HashSet<>(); + + /** + * When a Result is returned it can be healthy or unhealthy. In both cases it is associated to a + * Http 200 status. When an exception is thrown it means the server is no longer working at all, + * it is associated to a Http 500 status. + */ + @Override + protected HealthCheck.Result check() throws Exception { + StringBuilder messageBuilder = new StringBuilder(); + boolean first = true; + for (String unhealthyCounter : this.unhealthyCounters) { + if (metricRegistry.getNames().contains(unhealthyCounter)) { + Counter counter = metricRegistry.counter(unhealthyCounter); + if (counter.getCount() != 0) { + if (first) { + first = false; + } else { + messageBuilder.append("\n"); + } + messageBuilder.append(unhealthyCounter); + messageBuilder.append(" = "); + messageBuilder.append(counter.getCount()); + } + } + } + if (first) { + return Result.healthy("No unhealthy counter found."); + } + return Result.unhealthy(messageBuilder.toString()); + } + + /** To record a counter which might make the server unhealthy if its count is not zero. */ + public void recordUnhealthyCounter(final String counterName) { + unhealthyCounters.add(counterName); + } +} diff --git a/core/src/main/java/org/mapfish/print/processor/ProcessorGraphNode.java b/core/src/main/java/org/mapfish/print/processor/ProcessorGraphNode.java index 17101752fd..a13fe11fbd 100644 --- a/core/src/main/java/org/mapfish/print/processor/ProcessorGraphNode.java +++ b/core/src/main/java/org/mapfish/print/processor/ProcessorGraphNode.java @@ -120,7 +120,7 @@ public BiMap getInputMapper() { */ public void toString(final StringBuilder builder, final int indent, final String parent) { this.processor.toString(builder, indent, parent); - for (ProcessorGraphNode dependency : this.dependencies) { + for (ProcessorGraphNode dependency : this.dependencies) { dependency.toString(builder, indent + 1, this.processor.toString()); } } @@ -182,8 +182,10 @@ protected Values compute() { private void executeProcess(final Processor process, final Values values) { final String timerName = - String.format( - "%s.compute.%s", ProcessorGraphNode.class.getName(), process.getClass().getName()); + MetricRegistry.name( + ProcessorGraphNode.class.getSimpleName(), + "compute", + process.getClass().getSimpleName()); final Timer.Context timerContext = this.node.metricRegistry.timer(timerName).time(); try { final In inputParameter = ProcessorUtils.populateInputParameter(process, values); @@ -219,7 +221,7 @@ private RuntimeException handleException( LOGGER.info("Error while executing process: {}", process, cause); // the processor is already canceled, so we don't care if something fails this.execContext.getContext().stopIfCanceled(); - this.node.metricRegistry.counter(timerName + ".error").inc(); + this.node.metricRegistry.counter(MetricRegistry.name(timerName, "error")).inc(); return Objects.requireNonNullElseGet( runtimeCause, () -> new PrintException("Failed to execute process:" + process, cause)); } diff --git a/core/src/main/java/org/mapfish/print/processor/jasper/JasperReportBuilder.java b/core/src/main/java/org/mapfish/print/processor/jasper/JasperReportBuilder.java index bafdda38bf..4a0e067c66 100644 --- a/core/src/main/java/org/mapfish/print/processor/jasper/JasperReportBuilder.java +++ b/core/src/main/java/org/mapfish/print/processor/jasper/JasperReportBuilder.java @@ -50,7 +50,7 @@ public final class JasperReportBuilder extends AbstractProcessor createLayerGraphics( final AreaOfInterest areaOfInterest = addAreaOfInterestLayer(mapValues, layers); final String mapKey = UUID.randomUUID().toString(); final List graphics = new ArrayList<>(layers.size()); - String timerName = getClass().getName() + ".buildLayers"; + final String timerName = MetricRegistry.name(getClass().getSimpleName(), "buildLayers"); try (Timer.Context ignored = this.metricRegistry.timer(timerName).time()) { int fileNumber = 0; for (LayerGroup layerGroup : LayerGroup.buildGroups(layers, pdfA)) { diff --git a/core/src/main/java/org/mapfish/print/servlet/MapPrinterServlet.java b/core/src/main/java/org/mapfish/print/servlet/MapPrinterServlet.java index 27b6071690..91501f6338 100644 --- a/core/src/main/java/org/mapfish/print/servlet/MapPrinterServlet.java +++ b/core/src/main/java/org/mapfish/print/servlet/MapPrinterServlet.java @@ -1,7 +1,11 @@ package org.mapfish.print.servlet; +import static com.codahale.metrics.MetricRegistry.name; import static org.mapfish.print.servlet.ServletMapPrinterFactory.DEFAULT_CONFIGURATION_FILE_KEY; +import com.codahale.metrics.Counter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; import io.sentry.Sentry; import java.io.ByteArrayOutputStream; import java.io.File; @@ -81,17 +85,25 @@ public class MapPrinterServlet extends BaseMapServlet { /** The url path to get a sample print request. */ public static final String EXAMPLE_REQUEST_URL = "/exampleRequest.json"; + private static final String BUILDREPORT = "buildreport"; + /** The url path to create and get a report. */ - public static final String CREATE_AND_GET_URL = "/buildreport"; + public static final String CREATE_AND_GET_URL = "/" + BUILDREPORT; + + private static final String STATUS = "status"; /** The url path to get the status for a print task. */ - public static final String STATUS_URL = "/status"; + public static final String STATUS_URL = "/" + STATUS; + + private static final String CANCEL = "cancel"; /** The url path to cancel a print task. */ - public static final String CANCEL_URL = "/cancel"; + public static final String CANCEL_URL = "/" + CANCEL; + + private static final String REPORT = "report"; /** The url path to create a print task and to get a finished print. */ - public static final String REPORT_URL = "/report"; + public static final String REPORT_URL = "/" + REPORT; /** The url path to get the list of fonts available to geotools. */ public static final String FONTS_URL = "/fonts"; @@ -125,7 +137,7 @@ public class MapPrinterServlet extends BaseMapServlet { * Part of the {@link #getStatus(String, String, javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse)} response */ - public static final String JSON_STATUS = "status"; + public static final String JSON_STATUS = STATUS; /** * The elapsed time in ms from the point the job started. If the job is finished, this is the @@ -206,6 +218,7 @@ public class MapPrinterServlet extends BaseMapServlet { private static final List REQUEST_ID_HEADERS = Arrays.asList( "X-Request-ID", "X-Correlation-ID", "Request-ID", "X-Varnish", "X-Amzn-Trace-Id"); + private static final String NO_APP_ID = "NoAppId"; static { Handler.configureProtocolHandler(); @@ -218,6 +231,13 @@ public class MapPrinterServlet extends BaseMapServlet { private final ServletInfo servletInfo; private final MapPrinterFactory mapPrinterFactory; + private final Timer buildReportTimer; + private final Timer reportTimer; + private final Timer statusTimer; + private final Timer cancelTimer; + private final Timer getReportTimer; + private final Counter noAppIdCounter; + private final Counter withAppIdCounter; private long maxCreateAndGetWaitTimeInSeconds = ThreadPoolJobManager.DEFAULT_TIMEOUT_IN_SECONDS; @Autowired @@ -227,7 +247,8 @@ public MapPrinterServlet( final MapPrinterFactory printerFactory, final ApplicationContext context, final ServletInfo servletInfo, - final MapPrinterFactory mapPrinterFactory) { + final MapPrinterFactory mapPrinterFactory, + final MetricRegistry metricRegistry) { this.jobManager = jobManager; this.reportLoaders = reportLoaders; this.printerFactory = printerFactory; @@ -235,6 +256,21 @@ public MapPrinterServlet( this.servletInfo = servletInfo; this.mapPrinterFactory = mapPrinterFactory; + buildReportTimer = + metricRegistry.timer(name(MapPrinterServlet.class.getSimpleName(), BUILDREPORT)); + reportTimer = + metricRegistry.timer(name(MapPrinterServlet.class.getSimpleName(), "generate", REPORT)); + statusTimer = + metricRegistry.timer(name(MapPrinterServlet.class.getSimpleName(), STATUS, REPORT)); + cancelTimer = + metricRegistry.timer(name(MapPrinterServlet.class.getSimpleName(), CANCEL, REPORT)); + getReportTimer = + metricRegistry.timer(name(MapPrinterServlet.class.getSimpleName(), "download", REPORT)); + noAppIdCounter = + metricRegistry.counter(name(MapPrinterServlet.class.getSimpleName(), NO_APP_ID)); + withAppIdCounter = + metricRegistry.counter(name(MapPrinterServlet.class.getSimpleName(), "withAppId")); + boolean enableSentry = System.getProperties().contains("sentry.dsn"); enableSentry |= System.getenv().containsKey("SENTRY_URL"); enableSentry |= System.getenv().containsKey("SENTRY_DSN"); @@ -352,7 +388,10 @@ public final void getStatusSpecificAppId( @Nonnull @PathVariable final String referenceId, final HttpServletRequest statusRequest, final HttpServletResponse statusResponse) { - getStatus(appId, referenceId, statusRequest, statusResponse); + withAppIdCounter.inc(); + try (Timer.Context ignored = statusTimer.time()) { + getStatus(appId, referenceId, statusRequest, statusResponse); + } } /** @@ -371,7 +410,10 @@ public final void getStatusPath( @Nonnull @PathVariable final String referenceId, final HttpServletRequest statusRequest, final HttpServletResponse statusResponse) { - getStatus("default", referenceId, statusRequest, statusResponse); + noAppIdCounter.inc(); + try (Timer.Context ignored = statusTimer.time()) { + getStatus("default", referenceId, statusRequest, statusResponse); + } } /** @@ -386,7 +428,7 @@ public final void getStatusPath( * @param statusRequest the request object * @param statusResponse the response object */ - public final void getStatus( + private void getStatus( @Nonnull final String applicationId, @Nonnull final String referenceId, final HttpServletRequest statusRequest, @@ -438,7 +480,10 @@ public final void cancelSpecificAppId( @Nonnull @PathVariable final String appId, @Nonnull @PathVariable final String referenceId, final HttpServletResponse statusResponse) { - cancel(appId, referenceId, statusResponse); + withAppIdCounter.inc(); + try (Timer.Context ignored = cancelTimer.time()) { + cancel(appId, referenceId, statusResponse); + } } /** @@ -453,7 +498,10 @@ public final void cancelSpecificAppId( @RequestMapping(value = CANCEL_URL + "/{referenceId:\\S+}", method = RequestMethod.DELETE) public final void cancelPath( @Nonnull @PathVariable final String referenceId, final HttpServletResponse statusResponse) { - cancel("default", referenceId, statusResponse); + noAppIdCounter.inc(); + try (Timer.Context ignored = cancelTimer.time()) { + cancel("default", referenceId, statusResponse); + } } /** @@ -466,7 +514,7 @@ public final void cancelPath( * @param referenceId the job reference * @param statusResponse the response object */ - public final void cancel( + private void cancel( @Nonnull final String applicationId, @Nonnull final String referenceId, final HttpServletResponse statusResponse) { @@ -498,7 +546,20 @@ public final void createReport( final HttpServletRequest createReportRequest, final HttpServletResponse createReportResponse) throws NoSuchAppException { - setNoCache(createReportResponse); + withAppIdCounter.inc(); + try (Timer.Context ignored = reportTimer.time()) { + setNoCache(createReportResponse); + doCreateReport(appId, format, requestData, createReportRequest, createReportResponse); + } + } + + private void doCreateReport( + final String appId, + final String format, + final String requestData, + final HttpServletRequest createReportRequest, + final HttpServletResponse createReportResponse) + throws NoSuchAppException { String ref = createAndSubmitPrintJob( appId, format, requestData, createReportRequest, createReportResponse); @@ -540,7 +601,10 @@ public final void getReportSpecificAppId( @RequestParam(value = "inline", defaultValue = "false") final boolean inline, final HttpServletResponse getReportResponse) throws IOException, ServletException { - getReport(appId, referenceId, inline, getReportResponse); + withAppIdCounter.inc(); + try (Timer.Context ignored = getReportTimer.time()) { + getReport(appId, referenceId, inline, getReportResponse); + } } /** @@ -556,7 +620,10 @@ public final void getReportPath( @RequestParam(value = "inline", defaultValue = "false") final boolean inline, final HttpServletResponse getReportResponse) throws IOException, ServletException { - getReport("default", referenceId, inline, getReportResponse); + noAppIdCounter.inc(); + try (Timer.Context ignored = getReportTimer.time()) { + getReport("default", referenceId, inline, getReportResponse); + } } /** @@ -567,7 +634,7 @@ public final void getReportPath( * @param inline whether to inline the * @param getReportResponse the response object */ - public final void getReport( + private void getReport( @Nonnull final String applicationId, @Nonnull final String referenceId, final boolean inline, @@ -595,16 +662,29 @@ public final void createReport( final HttpServletRequest createReportRequest, final HttpServletResponse createReportResponse) throws NoSuchAppException { - setNoCache(createReportResponse); + noAppIdCounter.inc(); + try (Timer.Context ignored = reportTimer.time()) { + setNoCache(createReportResponse); + final String appId = getAppId(requestData, createReportResponse); + if (appId == null) { + return; + } + doCreateReport(appId, format, requestData, createReportRequest, createReportResponse); + } + } + + private static String getAppId( + final String requestData, final HttpServletResponse createReportResponse) + throws NoSuchAppException { PJsonObject spec = parseJson(requestData, createReportResponse); if (spec == null) { - return; + return null; } final String appId = spec.optString(JSON_APP, DEFAULT_CONFIGURATION_FILE_KEY); if (appId == null) { throw new NoSuchAppException("No app specified"); } - createReport(appId, format, requestData, createReportRequest, createReportResponse); + return appId; } /** @@ -629,8 +709,22 @@ public final void createReportAndGet( final HttpServletRequest createReportRequest, final HttpServletResponse createReportResponse) throws IOException, ServletException, InterruptedException, NoSuchAppException { - setNoCache(createReportResponse); + withAppIdCounter.inc(); + try (Timer.Context ignored = buildReportTimer.time()) { + setNoCache(createReportResponse); + doCreateReportAndGet( + appId, format, requestData, inline, createReportRequest, createReportResponse); + } + } + private void doCreateReportAndGet( + final String appId, + final String format, + final String requestData, + final boolean inline, + final HttpServletRequest createReportRequest, + final HttpServletResponse createReportResponse) + throws NoSuchAppException, InterruptedException, IOException, ServletException { String ref = createAndSubmitPrintJob( appId, format, requestData, createReportRequest, createReportResponse); @@ -668,17 +762,16 @@ public final void createReportAndGetNoAppId( final HttpServletRequest createReportRequest, final HttpServletResponse createReportResponse) throws IOException, ServletException, InterruptedException, NoSuchAppException { - setNoCache(createReportResponse); - PJsonObject spec = parseJson(requestData, createReportResponse); - if (spec == null) { - return; - } - String appId = spec.optString(JSON_APP, DEFAULT_CONFIGURATION_FILE_KEY); - if (appId == null) { - throw new NoSuchAppException("No app specified"); + noAppIdCounter.inc(); + try (Timer.Context ignored = buildReportTimer.time()) { + setNoCache(createReportResponse); + final String appId = getAppId(requestData, createReportResponse); + if (appId == null) { + return; + } + doCreateReportAndGet( + appId, format, requestData, inline, createReportRequest, createReportResponse); } - createReportAndGet( - appId, format, requestData, inline, createReportRequest, createReportResponse); } /** diff --git a/core/src/main/java/org/mapfish/print/servlet/job/Accounting.java b/core/src/main/java/org/mapfish/print/servlet/job/Accounting.java index 3d7f423ab2..5290f40a05 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/Accounting.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/Accounting.java @@ -8,7 +8,8 @@ /** Do some accounting for jobs. */ public class Accounting { - @Autowired private MetricRegistry metricRegistry; + /** The registry for all the metrics. */ + @Autowired protected MetricRegistry metricRegistry; /** * Start accounting for a job. @@ -65,7 +66,8 @@ public void onJobError() { } private String getMetricName(final String kind) { - return getClass().getName() + "." + StatsUtils.quotePart(this.entry.getAppId()) + "." + kind; + return MetricRegistry.name( + getClass().getSimpleName(), StatsUtils.quotePart(this.entry.getAppId()), kind); } } } diff --git a/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccounting.java b/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccounting.java index 7fb81f5c78..79ff164209 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccounting.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/HibernateAccounting.java @@ -1,9 +1,12 @@ package org.mapfish.print.servlet.job; +import com.codahale.metrics.MetricRegistry; +import javax.annotation.Nonnull; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.mapfish.print.config.Configuration; +import org.mapfish.print.metrics.UnhealthyCountersHealthCheck; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -17,8 +20,8 @@ public class HibernateAccounting extends Accounting { private static final Logger LOGGER = LoggerFactory.getLogger(HibernateAccounting.class); @Autowired private SessionFactory sf; - @Autowired private PlatformTransactionManager txManager; + @Autowired private UnhealthyCountersHealthCheck unhealthyCountersHealthCheck; @Override public JobTracker startJob(final PrintJobEntry entry, final Configuration configuration) { @@ -39,16 +42,15 @@ protected JobTracker(final PrintJobEntry entry, final Configuration configuratio @Override public long onJobSuccess(final PrintJob.PrintResult printResult) { - final long duractionUSec = super.onJobSuccess(printResult); - final HibernateAccountingEntry accountingEntry1 = + final long jobDurationInNanoSec = super.onJobSuccess(printResult); + final HibernateAccountingEntry accountingEntry = new HibernateAccountingEntry( this.entry, PrintJobStatus.Status.FINISHED, this.configuration); - final HibernateAccountingEntry accountingEntry = accountingEntry1; - accountingEntry.setProcessingTimeMS(duractionUSec / 1000000L); + accountingEntry.setProcessingTimeMS(jobDurationInNanoSec / 1000000L); accountingEntry.setFileSize(printResult.fileSize); accountingEntry.setStats(printResult.executionContext.getStats()); insertRecord(accountingEntry); - return duractionUSec; + return jobDurationInNanoSec; } @Override @@ -75,7 +77,7 @@ private void insertRecord(final HibernateAccountingEntry tuple) { tmpl.execute( new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(final TransactionStatus status) { + protected void doInTransactionWithoutResult(@Nonnull final TransactionStatus status) { final Session currentSession = HibernateAccounting.this.sf.getCurrentSession(); currentSession.merge(tuple); currentSession.flush(); @@ -83,7 +85,12 @@ protected void doInTransactionWithoutResult(final TransactionStatus status) { } }); } catch (HibernateException ex) { - LOGGER.warn("Cannot save accounting information", ex); + String name = + MetricRegistry.name( + getClass().getSimpleName(), "insertRecordInHibernateFailedThenSkiped"); + metricRegistry.counter(name).inc(); + unhealthyCountersHealthCheck.recordUnhealthyCounter(name); + LOGGER.error("Cannot save accounting information", ex); } } } diff --git a/core/src/main/java/org/mapfish/print/servlet/job/PrintJob.java b/core/src/main/java/org/mapfish/print/servlet/job/PrintJob.java index 5a7e6105cc..33c1f6f42c 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/PrintJob.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/PrintJob.java @@ -32,6 +32,7 @@ import org.mapfish.print.MapPrinter; import org.mapfish.print.MapPrinterFactory; import org.mapfish.print.config.Configuration; +import org.mapfish.print.config.ReportStorage; import org.mapfish.print.config.SmtpConfig; import org.mapfish.print.config.Template; import org.mapfish.print.config.WorkingDirectories; @@ -127,7 +128,10 @@ protected abstract PrintJobResult createResult( @Override public final PrintJobResult call() throws Exception { SecurityContextHolder.setContext(this.securityContext); - final Timer.Context timer = this.metricRegistry.timer(getClass().getName() + ".call").time(); + final Timer.Context timer = + this.metricRegistry + .timer(MetricRegistry.name(getClass().getSimpleName(), "RealReportGenerationDuration")) + .time(); MDC.put(Processor.MDC_APPLICATION_ID_KEY, this.entry.getAppId()); MDC.put(Processor.MDC_JOB_ID_KEY, this.entry.getReferenceId()); LOGGER.info( @@ -151,7 +155,9 @@ public final PrintJobResult call() throws Exception { entry.getRequestData(), outputStream)); - this.metricRegistry.counter(getClass().getName() + ".success").inc(); + this.metricRegistry + .counter(MetricRegistry.name(getClass().getSimpleName(), "SuccessfullyGeneratedReport")) + .inc(); LOGGER.info("Successfully completed print job {}", this.entry.getReferenceId()); LOGGER.debug("Job {}\n{}", this.entry.getReferenceId(), this.entry.getRequestData()); final String fileName = getFileName(mapPrinter, spec); @@ -172,7 +178,9 @@ public final PrintJobResult call() throws Exception { if (Thread.currentThread().isInterrupted()) { LOGGER.info( "Print job canceled {}\n{}", this.entry.getRequestData(), this.entry.getReferenceId()); - this.metricRegistry.counter(getClass().getName() + ".canceled").inc(); + this.metricRegistry + .counter(MetricRegistry.name(getClass().getSimpleName(), "ReportGenerationInterrupted")) + .inc(); jobTracker.onJobCancel(); } else { LOGGER.warn( @@ -180,7 +188,7 @@ public final PrintJobResult call() throws Exception { this.entry.getRequestData(), this.entry.getReferenceId(), e); - this.metricRegistry.counter(getClass().getName() + ".error").inc(); + this.metricRegistry.counter(MetricRegistry.name(getClass().getSimpleName(), "error")).inc(); jobTracker.onJobError(); } deleteReport(); @@ -191,10 +199,7 @@ public final PrintJobResult call() throws Exception { final long computationTimeMs = TimeUnit.MILLISECONDS.convert(timer.stop(), TimeUnit.NANOSECONDS); this.metricRegistry - .timer(getClass().getName() + ".total") - .update(totalTimeMS, TimeUnit.MILLISECONDS); - this.metricRegistry - .timer(getClass().getName() + ".wait") + .timer(MetricRegistry.name(getClass().getSimpleName(), "DelayBeforeReportGeneration")) .update(totalTimeMS - computationTimeMs, TimeUnit.MILLISECONDS); LOGGER.debug( "Print Job {} completed in {}ms", this.entry.getReferenceId(), computationTimeMs); @@ -237,9 +242,10 @@ private void sendErrorEmail(final SmtpConfig config, final PJsonObject request, message.setContent(multipart); LOGGER.info("Emailing error to {}", to); - Timer.Context timer = this.metricRegistry.timer(getClass().getName() + ".email.success").time(); - Transport.send(message); - timer.stop(); + String timerName = MetricRegistry.name(getClass().getSimpleName(), "SendingErrorEmail"); + try (Timer.Context ignored = this.metricRegistry.timer(timerName).time()) { + Transport.send(message); + } } private Message createMessage(final SmtpConfig config, final InternetAddress[] recipients) @@ -283,15 +289,15 @@ private void sendEmail( message.setSubject(request.optString("subject", config.getSubject())); String msg = request.optString("body", config.getBody()); - if (config.getStorage() != null) { - final Timer.Context saveTimer = - this.metricRegistry.timer(config.getStorage().getClass().getName()).time(); - final URL url = - config - .getStorage() - .save( - this.entry.getReferenceId(), fileName, fileExtension, mimeType, getReportFile()); - saveTimer.stop(); + final ReportStorage storage = config.getStorage(); + if (storage != null) { + URL url; + String timerName = storage.getClass().getSimpleName(); + try (Timer.Context ignored = this.metricRegistry.timer(timerName).time()) { + url = + storage.save( + this.entry.getReferenceId(), fileName, fileExtension, mimeType, getReportFile()); + } msg = msg.replace("{url}", url.toString()); } final MimeBodyPart html = new MimeBodyPart(); @@ -300,7 +306,7 @@ private void sendEmail( Multipart multipart = new MimeMultipart(); multipart.addBodyPart(html); - if (config.getStorage() == null) { + if (storage == null) { final MimeBodyPart attachment = new MimeBodyPart(); attachment.attachFile(getReportFile(), mimeType, null); attachment.setFileName(fileName + "." + fileExtension); @@ -310,10 +316,11 @@ private void sendEmail( message.setContent(multipart); LOGGER.info("Emailing result to {}", to); - Timer.Context timer = this.metricRegistry.timer(getClass().getName() + ".email.error").time(); - Transport.send(message); - timer.stop(); - stats.addEmailStats(recipients, config.getStorage() != null); + String timerName = MetricRegistry.name(getClass().getSimpleName(), "SendingResultEmail"); + try (Timer.Context ignored = this.metricRegistry.timer(timerName).time()) { + Transport.send(message); + } + stats.addEmailStats(recipients, storage != null); } /** Delete the report (used if the report is sent by email). */ diff --git a/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java b/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java index 20dfe2b28d..fee1c3dd2d 100644 --- a/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java +++ b/core/src/main/java/org/mapfish/print/servlet/job/impl/ThreadPoolJobManager.java @@ -331,9 +331,11 @@ protected PrintJob createJob(final PrintJobEntry entry) { private void submitInternal(final PrintJobEntry jobEntry) { final long numberOfWaitingRequests = this.jobQueue.getWaitingJobsCount(); if (numberOfWaitingRequests >= this.maxNumberOfWaitingJobs) { - metricRegistry.counter(getClass().getName() + ".queue_overflow").inc(); + metricRegistry + .counter(MetricRegistry.name(getClass().getSimpleName(), "queueOverflow")) + .inc(); throw new RuntimeException( - "Max. number of waiting print job requests exceeded. Number of waiting requests are: " + "Max. number of waiting print job requests exceeded. Number of waiting requests are: " + numberOfWaitingRequests); } jobEntry.assertAccess(); diff --git a/core/src/main/resources/mapfish-spring-application-context.xml b/core/src/main/resources/mapfish-spring-application-context.xml index 6583901b77..aaf2d532dd 100644 --- a/core/src/main/resources/mapfish-spring-application-context.xml +++ b/core/src/main/resources/mapfish-spring-application-context.xml @@ -57,7 +57,8 @@ - + + diff --git a/core/src/test/java/org/mapfish/print/metrics/ApplicationStatusTest.java b/core/src/test/java/org/mapfish/print/metrics/JobQueueHealthCheckTest.java similarity index 84% rename from core/src/test/java/org/mapfish/print/metrics/ApplicationStatusTest.java rename to core/src/test/java/org/mapfish/print/metrics/JobQueueHealthCheckTest.java index e98c8a7737..b986a2e404 100644 --- a/core/src/test/java/org/mapfish/print/metrics/ApplicationStatusTest.java +++ b/core/src/test/java/org/mapfish/print/metrics/JobQueueHealthCheckTest.java @@ -18,13 +18,13 @@ import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -public class ApplicationStatusTest extends AbstractMapfishSpringTest { +public class JobQueueHealthCheckTest extends AbstractMapfishSpringTest { @Mock private JobQueue jobQueue; @Mock private ThreadPoolJobManager jobManager; - @Autowired @InjectMocks private ApplicationStatus applicationStatus; + @Autowired @InjectMocks private JobQueueHealthCheck jobQueueHealthCheck; @Before public void setUp() throws Exception { @@ -36,7 +36,7 @@ public void setUp() throws Exception { public void testCheck_Success_NoPrintJobs() throws Exception { when(jobQueue.getWaitingJobsCount()).thenReturn(0L); - HealthCheck.Result result = applicationStatus.check(); + HealthCheck.Result result = jobQueueHealthCheck.check(); assertTrue(result.isHealthy()); assertEquals("No print job is waiting in the queue.", result.getMessage()); @@ -52,7 +52,7 @@ public void testCheck_Failed_NoPrintJobs() throws Exception { RuntimeException.class, () -> { // WHEN - applicationStatus.check(); + jobQueueHealthCheck.check(); }); assertEquals( @@ -65,8 +65,8 @@ public void testCheck_Success_PrintJobs() throws Exception { when(jobQueue.getWaitingJobsCount()).thenReturn(5L, 4L); when(jobManager.getLastExecutedJobTimestamp()).thenReturn(new Date()); - applicationStatus.check(); - HealthCheck.Result result = applicationStatus.check(); + jobQueueHealthCheck.check(); + HealthCheck.Result result = jobQueueHealthCheck.check(); assertTrue(result.isHealthy()); assertTrue(result.getMessage().contains("This server instance is printing.")); @@ -77,8 +77,8 @@ public void testCheck_Fail_TooManyJobsAreQueued() throws Exception { when(jobQueue.getWaitingJobsCount()).thenReturn(4L, 5L); when(jobManager.getLastExecutedJobTimestamp()).thenReturn(new Date()); - applicationStatus.check(); - HealthCheck.Result result = applicationStatus.check(); + jobQueueHealthCheck.check(); + HealthCheck.Result result = jobQueueHealthCheck.check(); assertFalse(result.isHealthy()); assertTrue(result.getMessage().contains("Number of print jobs queued is above threshold: ")); diff --git a/core/src/test/java/org/mapfish/print/metrics/UnhealthyCountersHealthCheckTest.java b/core/src/test/java/org/mapfish/print/metrics/UnhealthyCountersHealthCheckTest.java new file mode 100644 index 0000000000..850331f8be --- /dev/null +++ b/core/src/test/java/org/mapfish/print/metrics/UnhealthyCountersHealthCheckTest.java @@ -0,0 +1,81 @@ +package org.mapfish.print.metrics; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.health.HealthCheck; +import java.util.TreeSet; +import org.junit.Before; +import org.junit.Test; +import org.mapfish.print.AbstractMapfishSpringTest; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; + +public class UnhealthyCountersHealthCheckTest extends AbstractMapfishSpringTest { + @Mock private MetricRegistry metricRegistry; + + @Autowired @InjectMocks private UnhealthyCountersHealthCheck unhealthyCountersHealthCheck; + + @Before + public void setUp() throws Exception { + // Initialize mocks created above + MockitoAnnotations.openMocks(this); + } + + @Test + public void testCheck_Success_WithEmptyCounters() throws Exception { + MetricRegistry metricRegistryImpl = new MetricRegistry(); + TreeSet stringTreeSet = new TreeSet<>(); + when(metricRegistry.getNames()).thenReturn(stringTreeSet); + registerCounter("Some counter", metricRegistryImpl, stringTreeSet); + registerCounter("Some other counter", metricRegistryImpl, stringTreeSet); + + HealthCheck.Result result = unhealthyCountersHealthCheck.check(); + + assertTrue(result.isHealthy()); + assertEquals("No unhealthy counter found.", result.getMessage()); + } + + private Counter registerCounter( + final String counterName, + final MetricRegistry metricRegistryImpl, + final TreeSet stringTreeSet) { + Counter counter = metricRegistryImpl.counter(counterName); + stringTreeSet.add(counterName); + when(metricRegistry.counter(counterName)).thenReturn(counter); + + unhealthyCountersHealthCheck.recordUnhealthyCounter(counterName); + return counter; + } + + @Test + public void testCheck_Success_NoCounters() throws Exception { + HealthCheck.Result result = unhealthyCountersHealthCheck.check(); + + assertTrue(result.isHealthy()); + assertEquals("No unhealthy counter found.", result.getMessage()); + } + + @Test + public void testCheck_Fail_WithCounters() throws Exception { + MetricRegistry metricRegistryImpl = new MetricRegistry(); + TreeSet stringTreeSet = new TreeSet<>(); + when(metricRegistry.getNames()).thenReturn(stringTreeSet); + String counterName1 = "Some unhealthy counter"; + Counter c1 = registerCounter(counterName1, metricRegistryImpl, stringTreeSet); + c1.inc(); + String counterName2 = "Some other unhealthy counter"; + Counter c2 = registerCounter(counterName2, metricRegistryImpl, stringTreeSet); + c2.dec(); + + HealthCheck.Result result = unhealthyCountersHealthCheck.check(); + + assertFalse(result.isHealthy()); + assertEquals(counterName1 + " = 1\n" + counterName2 + " = -1", result.getMessage()); + } +} diff --git a/core/src/test/java/org/mapfish/print/servlet/MapPrinterServletSecurityTest.java b/core/src/test/java/org/mapfish/print/servlet/MapPrinterServletSecurityTest.java index e4ad36f631..c6d76b8370 100644 --- a/core/src/test/java/org/mapfish/print/servlet/MapPrinterServletSecurityTest.java +++ b/core/src/test/java/org/mapfish/print/servlet/MapPrinterServletSecurityTest.java @@ -8,6 +8,7 @@ import java.net.URISyntaxException; import java.util.Calendar; import java.util.HashMap; +import java.util.Objects; import org.json.JSONObject; import org.junit.After; import org.junit.Test; @@ -104,7 +105,7 @@ public void testCreateReportAndGet_RequestAllowed_OtherGetDenied() throws Except while (!done) { MockHttpServletRequest servletStatusRequest = new MockHttpServletRequest("GET", statusURL); MockHttpServletResponse servletStatusResponse = new MockHttpServletResponse(); - servlet.getStatus("test", ref, servletStatusRequest, servletStatusResponse); + servlet.getStatusSpecificAppId("test", ref, servletStatusRequest, servletStatusResponse); String contentAsString = servletStatusResponse.getContentAsString(); @@ -120,7 +121,7 @@ public void testCreateReportAndGet_RequestAllowed_OtherGetDenied() throws Except try { AccessAssertionTestUtil.setCreds("ROLE_USER"); final MockHttpServletResponse getResponse1 = new MockHttpServletResponse(); - this.servlet.getReport("test", ref, false, getResponse1); + this.servlet.getReportSpecificAppId("test", ref, false, getResponse1); fail("Expected an AccessDeniedException"); } catch (AccessDeniedException e) { // good @@ -129,7 +130,7 @@ public void testCreateReportAndGet_RequestAllowed_OtherGetDenied() throws Except try { final MockHttpServletResponse getResponse2 = new MockHttpServletResponse(); - this.servlet.getReport("test", ref, false, getResponse2); + this.servlet.getReportSpecificAppId("test", ref, false, getResponse2); assertEquals(HttpStatus.UNAUTHORIZED.value(), servletCreateResponse.getStatus()); fail("Expected an AuthenticationCredentialsNotFoundException"); } catch (AuthenticationCredentialsNotFoundException e) { @@ -137,7 +138,7 @@ public void testCreateReportAndGet_RequestAllowed_OtherGetDenied() throws Except } } - private byte[] assertCorrectResponse(MockHttpServletResponse servletGetReportResponse) + private void assertCorrectResponse(MockHttpServletResponse servletGetReportResponse) throws IOException { byte[] report; report = servletGetReportResponse.getContentAsByteArray(); @@ -146,12 +147,13 @@ private byte[] assertCorrectResponse(MockHttpServletResponse servletGetReportRes assertEquals("image/png", contentType); final Calendar instance = Calendar.getInstance(); int year = instance.get(Calendar.YEAR); - String fileName = servletGetReportResponse.getHeader("Content-disposition").split("=")[1]; + String fileName = + Objects.requireNonNull(servletGetReportResponse.getHeader("Content-disposition")) + .split("=")[1]; assertEquals("test_report-" + year + ".png", fileName); new ImageSimilarity(getFile(MapPrinterServletSecurityTest.class, "expectedSimpleImage.png")) .assertSimilarity(report, 0); - return report; } private void setUpConfigFiles() throws URISyntaxException { diff --git a/core/src/test/java/org/mapfish/print/servlet/job/PostResultToRegistryTaskTest.java b/core/src/test/java/org/mapfish/print/servlet/job/PostResultToRegistryTaskTest.java index 14abfb5f69..33f5d724ae 100644 --- a/core/src/test/java/org/mapfish/print/servlet/job/PostResultToRegistryTaskTest.java +++ b/core/src/test/java/org/mapfish/print/servlet/job/PostResultToRegistryTaskTest.java @@ -109,14 +109,13 @@ private class TestPrintJob extends PrintJob { entry.configureAccess(template, context); setSecurityContext(SecurityContextHolder.createEmptyContext()); } catch (JSONException e) { - e.printStackTrace(); throw new RuntimeException(e); } } @Override protected PrintResult withOpenOutputStream(PrintAction function) throws Exception { - return new PrintResult(42, new AbstractProcessor.Context(new HashMap())); + return new PrintResult(42, new AbstractProcessor.Context(new HashMap<>())); } @Override diff --git a/examples/src/test/java/org/mapfish/print/MetricsApiTest.java b/examples/src/test/java/org/mapfish/print/MetricsApiTest.java index 778d6c2f77..cce7d5d2ce 100644 --- a/examples/src/test/java/org/mapfish/print/MetricsApiTest.java +++ b/examples/src/test/java/org/mapfish/print/MetricsApiTest.java @@ -64,8 +64,10 @@ public void testHealthcheck() throws Exception { String bodyAsText = getBodyAsText(response); assertNotNull(bodyAsText); JSONObject healthcheck = new JSONObject(bodyAsText); - JSONObject application = healthcheck.getJSONObject("application"); - assertTrue(application.getBoolean("healthy")); + JSONObject jobQueueStatus = healthcheck.getJSONObject("jobQueueStatus"); + assertTrue(jobQueueStatus.getBoolean("healthy")); + JSONObject unhealthyCountersStatus = healthcheck.getJSONObject("unhealthyCountersStatus"); + assertTrue(unhealthyCountersStatus.getBoolean("healthy")); } }