diff --git a/src/main/java/hlf/java/rest/client/controller/ChaincodeOperationsController.java b/src/main/java/hlf/java/rest/client/controller/ChaincodeOperationsController.java index 8bc7325d..b9fdc90e 100644 --- a/src/main/java/hlf/java/rest/client/controller/ChaincodeOperationsController.java +++ b/src/main/java/hlf/java/rest/client/controller/ChaincodeOperationsController.java @@ -1,5 +1,6 @@ package hlf.java.rest.client.controller; +import hlf.java.rest.client.metrics.MetricsTrackedEndpoint; import hlf.java.rest.client.model.ChaincodeOperations; import hlf.java.rest.client.model.ChaincodeOperationsType; import hlf.java.rest.client.service.ChaincodeOperationsService; @@ -27,6 +28,10 @@ public class ChaincodeOperationsController { @Autowired private ChaincodeOperationsService chaincodeOperationsService; @PutMapping(value = "/operations") + @MetricsTrackedEndpoint( + name = "Chaincode Operations", + method = "PUT", + uri = "/chaincode/operations") public ResponseEntity performChaincodeOperation( @RequestParam("network_name") @Validated String networkName, @RequestParam("operations_type") @Validated ChaincodeOperationsType operationsType, @@ -48,6 +53,7 @@ public ResponseEntity performChaincodeOperation( } @GetMapping(value = "/sequence") + @MetricsTrackedEndpoint(name = "Get Sequence", method = "GET", uri = "/chaincode/sequence") public ResponseEntity getCurrentSequence( @RequestParam("network_name") @Validated String networkName, @RequestParam("chaincode_name") @Validated String chaincodeName, @@ -62,6 +68,7 @@ public ResponseEntity getCurrentSequence( } @GetMapping(value = "/packageId") + @MetricsTrackedEndpoint(name = "Get PackageId", method = "GET", uri = "/chaincode/packageId") public ResponseEntity getCurrentPackageId( @RequestParam("network_name") @Validated String networkName, @RequestParam("chaincode_name") @Validated String chaincodeName, @@ -77,6 +84,10 @@ public ResponseEntity getCurrentPackageId( } @GetMapping(value = "/approved-organisations") + @MetricsTrackedEndpoint( + name = "Fetch Approved Organizations", + method = "GET", + uri = "/chaincode/approved-organisations") public ResponseEntity> getApprovedOrganisationListForSmartContract( @RequestParam("network_name") @Validated String networkName, @RequestParam("chaincode_name") String chaincodeName, diff --git a/src/main/java/hlf/java/rest/client/controller/ChannelOperationController.java b/src/main/java/hlf/java/rest/client/controller/ChannelOperationController.java index a6adab0f..e8a6c626 100644 --- a/src/main/java/hlf/java/rest/client/controller/ChannelOperationController.java +++ b/src/main/java/hlf/java/rest/client/controller/ChannelOperationController.java @@ -1,5 +1,6 @@ package hlf.java.rest.client.controller; +import hlf.java.rest.client.metrics.MetricsTrackedEndpoint; import hlf.java.rest.client.model.ChannelOperationRequest; import hlf.java.rest.client.model.ClientResponseModel; import hlf.java.rest.client.service.ChannelService; @@ -23,6 +24,7 @@ public class ChannelOperationController { @Autowired private ChannelService channelService; @PostMapping("/create") + @MetricsTrackedEndpoint(name = "Create Channel", method = "POST", uri = "/channel/create") public ResponseEntity createChannel( @RequestBody ChannelOperationRequest channelCreationRequest) { ClientResponseModel response = channelService.createChannel(channelCreationRequest); @@ -30,6 +32,7 @@ public ResponseEntity createChannel( } @PostMapping("/join") + @MetricsTrackedEndpoint(name = "Join Channel", method = "POST", uri = "/channel/join") public ResponseEntity joinChannel( @RequestBody ChannelOperationRequest channelJoinRequest) { ClientResponseModel response = channelService.joinChannel(channelJoinRequest); diff --git a/src/main/java/hlf/java/rest/client/controller/FabricClientController.java b/src/main/java/hlf/java/rest/client/controller/FabricClientController.java index e6ca9f01..205a00f0 100644 --- a/src/main/java/hlf/java/rest/client/controller/FabricClientController.java +++ b/src/main/java/hlf/java/rest/client/controller/FabricClientController.java @@ -1,5 +1,6 @@ package hlf.java.rest.client.controller; +import hlf.java.rest.client.metrics.MetricsTrackedEndpoint; import hlf.java.rest.client.model.ClientResponseModel; import hlf.java.rest.client.model.EventAPIResponseModel; import hlf.java.rest.client.model.MultiDataTransactionPayload; @@ -42,6 +43,7 @@ public class FabricClientController { * @return responseEntity ResponseEntity Transaction Response */ @GetMapping(value = "/write_transaction") + @MetricsTrackedEndpoint(name = "Write Transaction", method = "GET", uri = "/write_transaction") public ResponseEntity postTransaction( @RequestParam("network_name") @Validated String networkName, @RequestParam("contract_name") @Validated String contractName, @@ -69,6 +71,7 @@ public ResponseEntity postTransaction( * @return responseEntity ResponseEntity Transaction Response */ @PostMapping(value = "/init_transaction") + @MetricsTrackedEndpoint(name = "Initialise Chaincode", method = "POST", uri = "/init_transaction") public ResponseEntity initTransaction( @RequestHeader("channel") @Validated String channelName, @RequestHeader("chaincode") @Validated String chaincodeName, @@ -103,6 +106,7 @@ public ResponseEntity initTransaction( * @return responseEntity ResponseEntity Transaction Response */ @PostMapping(value = "/invoke_transaction") + @MetricsTrackedEndpoint(name = "Invoke Transaction", method = "POST", uri = "/invoke_transaction") public ResponseEntity invokeTransaction( @RequestHeader("channel") @Validated String channelName, @RequestHeader("chaincode") @Validated String chaincodeName, @@ -171,6 +175,7 @@ public ResponseEntity invokeTransaction( * @return responseEntity ResponseEntity Transaction Response */ @GetMapping(value = "/query_transaction") + @MetricsTrackedEndpoint(name = "Query Transaction", method = "GET", uri = "/query_transaction") public ResponseEntity getTransaction( @RequestParam("channel") @Validated String networkName, @RequestParam("chaincode") @Validated String contractName, @@ -212,6 +217,10 @@ public ResponseEntity getTransaction( * @return the EventAPIResponseModel which contain all the events */ @GetMapping(value = "/blocks/{block-number}/transactions/{transaction-id}/events") + @MetricsTrackedEndpoint( + name = "Query Transaction By Block Number", + method = "GET", + uri = "/blocks/{block-number}/transactions/{transaction-id}/events") public ResponseEntity getTransactionByBlockNumber( @PathVariable("transaction-id") String transactionId, @PathVariable("block-number") Long blockNumber, @@ -237,6 +246,10 @@ public ResponseEntity getTransactionByBlockNumber( * @return responseEntity ResponseEntity Transaction Response */ @PostMapping(value = "/invoke_transaction/v2") + @MetricsTrackedEndpoint( + name = "Invoke Transaction V2", + method = "POST", + uri = "/invoke_transaction/v2") public ResponseEntity invokeTransaction( @RequestParam("channel") @Validated String channelName, @RequestParam("chaincode") @Validated String chaincodeName, diff --git a/src/main/java/hlf/java/rest/client/metrics/MetricsTrackedEndpoint.java b/src/main/java/hlf/java/rest/client/metrics/MetricsTrackedEndpoint.java new file mode 100644 index 00000000..6aa2cd47 --- /dev/null +++ b/src/main/java/hlf/java/rest/client/metrics/MetricsTrackedEndpoint.java @@ -0,0 +1,16 @@ +package hlf.java.rest.client.metrics; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface MetricsTrackedEndpoint { + String name(); + + String uri(); + + String method(); +} diff --git a/src/main/java/hlf/java/rest/client/metrics/MetricsTrackedEndpointAspect.java b/src/main/java/hlf/java/rest/client/metrics/MetricsTrackedEndpointAspect.java new file mode 100644 index 00000000..99682116 --- /dev/null +++ b/src/main/java/hlf/java/rest/client/metrics/MetricsTrackedEndpointAspect.java @@ -0,0 +1,37 @@ +package hlf.java.rest.client.metrics; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class MetricsTrackedEndpointAspect { + + @Autowired private MeterRegistry meterRegistry; + + private Map trackedEndpoints = new ConcurrentHashMap<>(); + + @After("@annotation(metricsTrackedEndpoint)") + public void afterTimedEndpoint( + JoinPoint joinPoint, MetricsTrackedEndpoint metricsTrackedEndpoint) { + + trackedEndpoints.computeIfAbsent( + metricsTrackedEndpoint.name(), + val -> { + Gauge.builder("tracked_endpoints", () -> 1L) + .tag("name", metricsTrackedEndpoint.name()) + .tag("method", metricsTrackedEndpoint.method()) + .tag("uri", metricsTrackedEndpoint.uri()) + .register(meterRegistry); + + return true; + }); + } +}