1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.federatedcompute.services.statsd; 18 19 import static com.android.federatedcompute.services.stats.FederatedComputeStatsLog.EXAMPLE_ITERATOR_NEXT_LATENCY_REPORTED; 20 import static com.android.federatedcompute.services.stats.FederatedComputeStatsLog.FEDERATED_COMPUTE_API_CALLED; 21 import static com.android.federatedcompute.services.stats.FederatedComputeStatsLog.FEDERATED_COMPUTE_TRAINING_EVENT_REPORTED; 22 23 import com.android.federatedcompute.services.stats.FederatedComputeStatsLog; 24 import com.android.internal.annotations.VisibleForTesting; 25 26 import com.google.common.util.concurrent.RateLimiter; 27 28 /** Log API stats and client error stats to StatsD. */ 29 public class FederatedComputeStatsdLogger { 30 private static volatile FederatedComputeStatsdLogger sFCStatsdLogger = null; 31 private final RateLimiter mRateLimiter; 32 33 @VisibleForTesting FederatedComputeStatsdLogger(RateLimiter rateLimiter)34 FederatedComputeStatsdLogger(RateLimiter rateLimiter) { 35 mRateLimiter = rateLimiter; 36 } 37 38 /** Returns an instance of {@link FederatedComputeStatsdLogger}. */ getInstance()39 public static FederatedComputeStatsdLogger getInstance() { 40 if (sFCStatsdLogger == null) { 41 synchronized (FederatedComputeStatsdLogger.class) { 42 if (sFCStatsdLogger == null) { 43 sFCStatsdLogger = 44 new FederatedComputeStatsdLogger( 45 // Android metrics team recommend the atom logging frequency 46 // should not exceed once per 10 milliseconds. 47 RateLimiter.create(100)); 48 } 49 } 50 } 51 return sFCStatsdLogger; 52 } 53 54 /** Log API call stats e.g. response code, API name etc. */ logApiCallStats(ApiCallStats apiCallStats)55 public void logApiCallStats(ApiCallStats apiCallStats) { 56 if (mRateLimiter.tryAcquire()) { 57 FederatedComputeStatsLog.write( 58 FEDERATED_COMPUTE_API_CALLED, 59 apiCallStats.getApiClass(), 60 apiCallStats.getApiName(), 61 apiCallStats.getLatencyMillis(), 62 apiCallStats.getResponseCode(), 63 apiCallStats.getSdkPackageName()); 64 } 65 } 66 67 /** 68 * Log FederatedComputeTrainingEventReported to track each stage of federated computation job 69 * execution. 70 */ logTrainingEventReported(TrainingEventReported trainingEvent)71 public void logTrainingEventReported(TrainingEventReported trainingEvent) { 72 if (mRateLimiter.tryAcquire()) { 73 FederatedComputeStatsLog.write( 74 FEDERATED_COMPUTE_TRAINING_EVENT_REPORTED, 75 trainingEvent.getClientVersion(), 76 trainingEvent.getEventKind(), 77 trainingEvent.getTaskId(), 78 trainingEvent.getDurationInMillis(), 79 trainingEvent.getExampleSize(), 80 trainingEvent.getDataTransferDurationMillis(), 81 trainingEvent.getBytesUploaded(), 82 trainingEvent.getBytesDownloaded(), 83 trainingEvent.getKeyAttestationLatencyMillis(), 84 trainingEvent.getExampleStoreBindLatencyNanos(), 85 trainingEvent.getExampleStoreStartQueryLatencyNanos(), 86 trainingEvent.getPopulationId(), 87 trainingEvent.getExampleCount(), 88 trainingEvent.getSdkPackageName()); 89 } 90 } 91 92 /** This method is only used to test if rate limiter is applied when logging to statsd. */ 93 @VisibleForTesting recordExampleIteratorLatencyMetrics(ExampleIteratorLatency iteratorLatency)94 boolean recordExampleIteratorLatencyMetrics(ExampleIteratorLatency iteratorLatency) { 95 if (mRateLimiter.tryAcquire()) { 96 FederatedComputeStatsLog.write( 97 EXAMPLE_ITERATOR_NEXT_LATENCY_REPORTED, 98 iteratorLatency.getClientVersion(), 99 iteratorLatency.getTaskId(), 100 iteratorLatency.getGetNextLatencyNanos()); 101 return true; 102 } 103 return false; 104 } 105 106 /** 107 * Log ExampleIteratorNextLatencyReported to track the latency of ExampleStoreIterator.next 108 * called. 109 */ logExampleIteratorNextLatencyReported(ExampleIteratorLatency iteratorLatency)110 public void logExampleIteratorNextLatencyReported(ExampleIteratorLatency iteratorLatency) { 111 var unused = recordExampleIteratorLatencyMetrics(iteratorLatency); 112 } 113 } 114