diff --git a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java index e765cd8d4994..4e188fda2f17 100644 --- a/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java +++ b/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/healthcare/FhirIO.java @@ -31,6 +31,7 @@ import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -240,6 +241,7 @@ "nullness" // TODO(https://issues.apache.org/jira/browse/BEAM-10402) }) public class FhirIO { + private static final String BASE_METRIC_PREFIX = "fhirio/"; /** * Read resources from a PCollection of resource IDs (e.g. when subscribing the pubsub @@ -497,11 +499,16 @@ public FhirIO.Read.Result expand(PCollection resourceIds) { /** DoFn for fetching messages from the Fhir store with error handling. */ static class ReadResourceFn extends DoFn { - private Counter failedMessageGets = - Metrics.counter(ReadResourceFn.class, "failed-message-reads"); private static final Logger LOG = LoggerFactory.getLogger(ReadResourceFn.class); - private final Counter successfulStringGets = - Metrics.counter(ReadResourceFn.class, "successful-hl7v2-message-gets"); + private static final Counter READ_RESOURCE_ERRORS = + Metrics.counter(ReadResourceFn.class, BASE_METRIC_PREFIX + "read_resource_error_count"); + private static final Counter READ_RESOURCE_SUCCESS = + Metrics.counter( + ReadResourceFn.class, BASE_METRIC_PREFIX + "read_resource_success_count"); + private static final Distribution READ_RESOURCE_LATENCY_MS = + Metrics.distribution( + ReadResourceFn.class, BASE_METRIC_PREFIX + "read_resource_latency_ms"); + private HealthcareApiClient client; private ObjectMapper mapper; @@ -530,7 +537,7 @@ public void processElement(ProcessContext context) { try { context.output(fetchResource(this.client, resourceId)); } catch (Exception e) { - failedMessageGets.inc(); + READ_RESOURCE_ERRORS.inc(); LOG.warn( String.format( "Error fetching Fhir message with ID %s writing to Dead Letter " @@ -542,14 +549,15 @@ public void processElement(ProcessContext context) { private String fetchResource(HealthcareApiClient client, String resourceId) throws IOException, IllegalArgumentException { - long startTime = System.currentTimeMillis(); + long startTime = Instant.now().toEpochMilli(); HttpBody resource = client.readFhirResource(resourceId); + READ_RESOURCE_LATENCY_MS.update(Instant.now().toEpochMilli() - startTime); if (resource == null) { throw new IOException(String.format("GET request for %s returned null", resourceId)); } - this.successfulStringGets.inc(); + READ_RESOURCE_SUCCESS.inc(); return mapper.writeValueAsString(resource); } } @@ -1289,7 +1297,16 @@ public FhirIO.Write.Result expand(PCollection input) { /** The type Write Fhir fn. */ static class ExecuteBundlesFn extends DoFn> { - private Counter failedBundles = Metrics.counter(ExecuteBundlesFn.class, "failed-bundles"); + private static final Counter EXECUTE_BUNDLE_ERRORS = + Metrics.counter( + ExecuteBundlesFn.class, BASE_METRIC_PREFIX + "execute_bundle_error_count"); + private static final Counter EXECUTE_BUNDLE_SUCCESS = + Metrics.counter( + ExecuteBundlesFn.class, BASE_METRIC_PREFIX + "execute_bundle_success_count"); + private static final Distribution EXECUTE_BUNDLE_LATENCY_MS = + Metrics.distribution( + ExecuteBundlesFn.class, BASE_METRIC_PREFIX + "execute_bundle_latency_ms"); + private transient HealthcareApiClient client; private final ObjectMapper mapper = new ObjectMapper(); /** The Fhir store. */ @@ -1314,20 +1331,18 @@ public void initClient() throws IOException { this.client = new HttpHealthcareApiClient(); } - /** - * Execute Bundles. - * - * @param context the context - */ @ProcessElement public void executeBundles(ProcessContext context) { String body = context.element(); try { + long startTime = Instant.now().toEpochMilli(); // Validate that data was set to valid JSON. mapper.readTree(body); client.executeFhirBundle(fhirStore.get(), body); + EXECUTE_BUNDLE_LATENCY_MS.update(Instant.now().toEpochMilli() - startTime); + EXECUTE_BUNDLE_SUCCESS.inc(); } catch (IOException | HealthcareHttpException e) { - failedBundles.inc(); + EXECUTE_BUNDLE_ERRORS.inc(); context.output(HealthcareIOError.of(body, e)); } } @@ -1596,13 +1611,17 @@ public FhirIO.Search.Result expand(PCollection> resourceI /** DoFn for searching messages from the Fhir store with error handling. */ class SearchResourcesFn extends DoFn, KV> { - private Distribution searchLatencyMs = - Metrics.distribution(SearchResourcesFn.class, "fhir-search-latency-ms"); - private Counter failedSearches = - Metrics.counter(SearchResourcesFn.class, "failed-fhir-searches"); + private final Counter searchResourceErrors = + Metrics.counter( + SearchResourcesFn.class, BASE_METRIC_PREFIX + "search_resource_error_count"); + private final Counter searchResourceSuccess = + Metrics.counter( + SearchResourcesFn.class, BASE_METRIC_PREFIX + "search_resource_success_count"); + private final Distribution searchResourceLatencyMs = + Metrics.distribution( + SearchResourcesFn.class, BASE_METRIC_PREFIX + "search_resource_latency_ms"); + private final Logger log = LoggerFactory.getLogger(SearchResourcesFn.class); - private final Counter successfulSearches = - Metrics.counter(SearchResourcesFn.class, "successful-fhir-searches"); private HealthcareApiClient client; private final ValueProvider fhirStore; @@ -1639,7 +1658,7 @@ public void processElement(ProcessContext context) { fhirSearchParameters.getResourceType(), fhirSearchParameters.getQueries()))); } catch (IllegalArgumentException | NoSuchElementException e) { - failedSearches.inc(); + searchResourceErrors.inc(); log.warn( String.format( "Error search FHIR messages writing to Dead Letter " @@ -1656,7 +1675,7 @@ private JsonArray searchResources( String resourceType, @Nullable Map parameters) throws NoSuchElementException { - long startTime = System.currentTimeMillis(); + long start = Instant.now().toEpochMilli(); HashMap parameterObjects = new HashMap<>(); if (parameters != null) { @@ -1670,8 +1689,8 @@ private JsonArray searchResources( while (iter.hasNext()) { result.addAll(iter.next()); } - searchLatencyMs.update(System.currentTimeMillis() - startTime); - this.successfulSearches.inc(); + searchResourceLatencyMs.update(java.time.Instant.now().toEpochMilli() - start); + searchResourceSuccess.inc(); return result; } }