From a2e3c06efe87fd17c69d017433efd99046403afc Mon Sep 17 00:00:00 2001 From: Shivd131 Date: Tue, 20 Jan 2026 21:22:21 +0530 Subject: [PATCH] FINERACT-2438: Add Micrometer Observability to Reporting API --- .../api/RunreportsApiResource.java | 41 +++++++++++++++---- .../src/main/resources/application.properties | 4 +- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/RunreportsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/RunreportsApiResource.java index 72213fc6320..d77b46cd3e3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/RunreportsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/RunreportsApiResource.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.infrastructure.dataqueries.api; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -63,6 +65,7 @@ public class RunreportsApiResource { private final PlatformSecurityContext context; private final ReadReportingService readExtraDataAndReportingService; private final ReportingProcessServiceProvider reportingProcessServiceProvider; + private final MeterRegistry meterRegistry; @GET @Path("/availableExports/{reportName}") @@ -134,23 +137,43 @@ public Response runReport(final String reportName, final UriInfo uriInfo, final } private Response processReportRequest(final String reportName, final UriInfo uriInfo, final boolean isSelfServiceUserReport) { + Timer.Sample sample = Timer.start(meterRegistry); MultivaluedMap queryParams = new MultivaluedStringMap(); queryParams.putAll(uriInfo.getQueryParameters()); final boolean parameterTypeValue = ApiParameterHelper.parameterType(queryParams); - checkUserPermissionForReport(reportName, parameterTypeValue); + String outputType = queryParams.getFirst("output-type"); + if (outputType == null) { + outputType = "HTML"; + } - // Pass through isSelfServiceUserReport so that ReportingProcessService implementations can use it - queryParams.putSingle(IS_SELF_SERVICE_USER_REPORT_PARAMETER, Boolean.toString(isSelfServiceUserReport)); + try { + checkUserPermissionForReport(reportName, parameterTypeValue); - String reportType = readExtraDataAndReportingService.getReportType(reportName, isSelfServiceUserReport, parameterTypeValue); - ReportingProcessService reportingProcessService = reportingProcessServiceProvider.findReportingProcessService(reportType); - if (reportingProcessService == null) { - throw new PlatformServiceUnavailableException("err.msg.report.service.implementation.missing", - ReportingProcessServiceProvider.SERVICE_MISSING + reportType, reportType); + queryParams.putSingle(IS_SELF_SERVICE_USER_REPORT_PARAMETER, Boolean.toString(isSelfServiceUserReport)); + + String reportType = readExtraDataAndReportingService.getReportType(reportName, isSelfServiceUserReport, parameterTypeValue); + ReportingProcessService reportingProcessService = reportingProcessServiceProvider.findReportingProcessService(reportType); + if (reportingProcessService == null) { + throw new PlatformServiceUnavailableException("err.msg.report.service.implementation.missing", + ReportingProcessServiceProvider.SERVICE_MISSING + reportType, reportType); + } + + Response response = reportingProcessService.processRequest(reportName, queryParams); + + // 2. Stop Timer (Success) + sample.stop(Timer.builder("fineract.report.execution").tag("name", reportName).tag("type", reportType).tag("format", outputType) + .tag("status", "success").register(meterRegistry)); + + return response; + + } catch (Exception e) { + // 3. Stop Timer (Failure) + sample.stop(Timer.builder("fineract.report.execution").tag("name", reportName).tag("format", outputType).tag("status", "failed") + .tag("exception", e.getClass().getSimpleName()).register(meterRegistry)); + throw e; } - return reportingProcessService.processRequest(reportName, queryParams); } private void checkUserPermissionForReport(final String reportName, final boolean parameterType) { diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index d002dfbb723..a180970f8d9 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -339,8 +339,8 @@ management.endpoints.web.cors.allowed-headers=* # FINERACT-883 management.info.git.mode=FULL -management.endpoints.web.exposure.include=${FINERACT_MANAGEMENT_ENDPOINT_WEB_EXPOSURE_INCLUDE:health,info,prometheus} - +management.endpoints.web.exposure.include=${FINERACT_MANAGEMENT_ENDPOINT_WEB_EXPOSURE_INCLUDE:health,info,metrics,prometheus} +management.endpoint.metrics.enabled=${FINERACT_MANAGEMENT_ENDPOINT_METRICS_ENABLED:false} management.tracing.enabled=${FINERACT_MANAGEMENT_TRACIING_ENABLED:false} management.metrics.tags.application=${FINERACT_MANAGEMENT_METRICS_TAGS_APPLICATION:fineract}