Skip to content

Commit 59b88e2

Browse files
prsaminathanPrvnkmr337
authored andcommitted
Adds BrokerPerformanceMetrics class and integrate performance metrics into token acquisition flow.
- Added BrokerPerformanceMetrics.java to hold broker request latency data. - AcquireTokenResult and BaseException hold instance of BrokerPerformanceMetrics for the related Broker request and response. - MsalBrokerResultAdapter updated to read BrokerPerformanceMetrics data from Broker result bundle to be populated in AcquireTokenResult and BaseException.
1 parent 7fd1e1e commit 59b88e2

File tree

5 files changed

+188
-3
lines changed

5 files changed

+188
-3
lines changed

common/src/main/java/com/microsoft/identity/common/internal/result/MsalBrokerResultAdapter.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
// THE SOFTWARE.
2323
package com.microsoft.identity.common.internal.result;
2424

25+
import static com.microsoft.identity.common.java.AuthenticationConstants.Broker.BROKER_REQUEST_RECEIVED_TIMESTAMP;
26+
import static com.microsoft.identity.common.java.AuthenticationConstants.Broker.BROKER_RESPONSE_GENERATION_TIMESTAMP;
2527
import static com.microsoft.identity.common.adal.internal.AuthenticationConstants.Broker.BROKER_ACCOUNTS;
2628
import static com.microsoft.identity.common.adal.internal.AuthenticationConstants.Broker.BROKER_ACCOUNTS_COMPRESSED;
2729
import static com.microsoft.identity.common.adal.internal.AuthenticationConstants.Broker.BROKER_ACTIVITY_NAME;
@@ -58,6 +60,7 @@
5860
import com.microsoft.identity.common.internal.request.AuthenticationSchemeTypeAdapter;
5961
import com.microsoft.identity.common.internal.util.GzipUtil;
6062
import com.microsoft.identity.common.java.authorities.AzureActiveDirectoryAudience;
63+
import com.microsoft.identity.common.java.broker.BrokerPerformanceMetrics;
6164
import com.microsoft.identity.common.java.cache.CacheRecord;
6265
import com.microsoft.identity.common.java.cache.ICacheRecord;
6366
import com.microsoft.identity.common.java.commands.AcquirePrtSsoTokenBatchResult;
@@ -117,6 +120,7 @@ public class MsalBrokerResultAdapter implements IBrokerResultAdapter {
117120
private static final String TAG = MsalBrokerResultAdapter.class.getSimpleName();
118121
public static final Gson GSON = new Gson();
119122

123+
private static final Long INVALID_TIMESTAMP = -1L;
120124
private static final String DCF_NOT_SUPPORTED_ERROR = "deviceCodeFlowAuthRequest() not supported in BrokerMsalController";
121125
private static final String WEBAPPS_ENTRY_IS_NULL_ERROR = "WebApps entry in the bundle is null";
122126
interface IBooleanCallback {
@@ -401,15 +405,53 @@ public BaseException getBaseExceptionFromBundle(@NonNull final Bundle resultBund
401405
}
402406

403407
final String exceptionType = brokerResult.getExceptionType();
408+
final BrokerPerformanceMetrics metrics = getBrokerPerformanceMetricsFromBundle(resultBundle);
409+
final BaseException baseException;
404410

405411
if (!StringUtil.isNullOrEmpty(exceptionType)) {
406-
return getBaseExceptionFromExceptionType(exceptionType, brokerResult);
412+
baseException = getBaseExceptionFromExceptionType(exceptionType, brokerResult);
407413
} else {
408414
// This code is here for legacy purposes where old versions of broker (3.1.8 or below)
409415
// wouldn't return exception type in the result.
410416
Logger.info(methodTag, "Exception type is not returned from the broker, " +
411417
"using error codes to transform to the right exception");
412-
return getBaseExceptionFromErrorCodes(brokerResult);
418+
baseException = getBaseExceptionFromErrorCodes(brokerResult);
419+
}
420+
421+
// Attach broker performance metrics if available
422+
if (metrics != null) {
423+
baseException.setBrokerPerformanceMetrics(metrics);
424+
}
425+
426+
return baseException;
427+
}
428+
429+
/**
430+
* Extracts broker performance metrics from the result bundle if available.
431+
*
432+
* @param resultBundle The result bundle returned from the broker.
433+
* @return {@link BrokerPerformanceMetrics} if available, null otherwise.
434+
*/
435+
@Nullable
436+
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
437+
public BrokerPerformanceMetrics getBrokerPerformanceMetricsFromBundle(@NonNull final Bundle resultBundle) {
438+
final long brokerRequestReceivedTimestamp = resultBundle.getLong(
439+
BROKER_REQUEST_RECEIVED_TIMESTAMP,
440+
INVALID_TIMESTAMP
441+
);
442+
final long brokerResponseGenerationTimestamp = resultBundle.getLong(
443+
BROKER_RESPONSE_GENERATION_TIMESTAMP,
444+
INVALID_TIMESTAMP
445+
);
446+
447+
if (brokerRequestReceivedTimestamp != INVALID_TIMESTAMP && brokerResponseGenerationTimestamp != INVALID_TIMESTAMP) {
448+
return new BrokerPerformanceMetrics(
449+
brokerRequestReceivedTimestamp,
450+
brokerResponseGenerationTimestamp
451+
);
452+
} else {
453+
Logger.warn(TAG, "Broker performance metrics not found in the result bundle.");
454+
return null;
413455
}
414456
}
415457

@@ -867,7 +909,11 @@ AcquireTokenResult getAcquireTokenResultFromResultBundle(@NonNull final Bundle r
867909
acquireTokenResult.setLocalAuthenticationResult(
868910
resultAdapter.authenticationResultFromBundle(resultBundle)
869911
);
870-
912+
// Set broker performance metrics if available
913+
final BrokerPerformanceMetrics brokerPerformanceMetrics = resultAdapter.getBrokerPerformanceMetricsFromBundle(resultBundle);
914+
if (brokerPerformanceMetrics != null) {
915+
acquireTokenResult.setBrokerPerformanceMetrics(brokerPerformanceMetrics);
916+
}
871917
return acquireTokenResult;
872918
}
873919

common/src/test/java/com/microsoft/identity/common/internal/request/MsalBrokerResultAdapterTests.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,46 @@ class MsalBrokerResultAdapterTests {
381381
assertEquals(mockErrorCode, receivedException.errorCode)
382382
assertEquals(mockErrorMessage, receivedException.message)
383383
}
384+
385+
@Test
386+
fun testGetBrokerPerformanceMetricsFromBundle_WithValidTimestamps() {
387+
val mockRequestReceivedTimestamp = 123456789L
388+
val mockResponseGenerationTimestamp = 987654321L
389+
val resultAdapter = MsalBrokerResultAdapter()
390+
391+
val resultBundle = android.os.Bundle().apply {
392+
putLong(
393+
com.microsoft.identity.common.java.AuthenticationConstants.Broker.BROKER_REQUEST_RECEIVED_TIMESTAMP,
394+
mockRequestReceivedTimestamp
395+
)
396+
putLong(
397+
com.microsoft.identity.common.java.AuthenticationConstants.Broker.BROKER_RESPONSE_GENERATION_TIMESTAMP,
398+
mockResponseGenerationTimestamp
399+
)
400+
}
401+
402+
val metrics = resultAdapter.getBrokerPerformanceMetricsFromBundle(resultBundle)
403+
404+
assertNotNull(metrics)
405+
406+
// Validate timestamp values
407+
assertEquals(mockRequestReceivedTimestamp, metrics!!.brokerRequestReceivedTimestamp)
408+
assertEquals(mockResponseGenerationTimestamp, metrics.brokerResponseGenerationTimestamp)
409+
410+
// Validate calculated broker handling time
411+
val expectedBrokerHandlingTime = mockResponseGenerationTimestamp - mockRequestReceivedTimestamp
412+
assertEquals(expectedBrokerHandlingTime, metrics.brokerHandlingTime)
413+
414+
// Validate response latency (should be >= 0)
415+
assertNotNull(metrics.responseLatency)
416+
assertTrue(metrics.responseLatency >= 0)
417+
}
418+
419+
@Test
420+
fun testGetBrokerPerformanceMetricsFromBundle_WithoutTimestamps() {
421+
val resultAdapter = MsalBrokerResultAdapter()
422+
val resultBundle = android.os.Bundle() // Empty bundle, no timestamps
423+
val metrics = resultAdapter.getBrokerPerformanceMetricsFromBundle(resultBundle)
424+
assertNull(metrics)
425+
}
384426
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.microsoft.identity.common.java.broker;
2+
3+
/**
4+
* Holds broker performance metrics derived from timestamps in authentication flows.
5+
* Calculates processing and latency durations at construction time.
6+
*/
7+
public class BrokerPerformanceMetrics {
8+
/**
9+
* Time spent by broker processing the request (in milliseconds).
10+
* Calculated as: brokerResponseGenerationTimestamp - brokerRequestReceivedTimestamp
11+
*/
12+
private final Long brokerHandlingTime;
13+
14+
/**
15+
* Time for the response to reach and be processed by the client (in milliseconds).
16+
* Calculated as: currentTime - brokerResponseGenerationTimestamp
17+
*/
18+
private final Long responseLatency;
19+
20+
21+
/**
22+
* Timestamp when the broker received the authentication request (epoch milliseconds).
23+
* Used to calculate broker handling time.
24+
*/
25+
private final Long brokerRequestReceivedTimestamp;
26+
27+
/**
28+
* Timestamp when the broker generated the authentication response (epoch milliseconds).
29+
* Used to calculate both broker handling time and response latency.
30+
*/
31+
private final Long brokerResponseGenerationTimestamp;
32+
33+
/**
34+
* Creates broker performance metrics with calculated durations.
35+
*
36+
* @param brokerRequestReceivedTimestamp When broker received the request (epoch millis)
37+
* @param brokerResponseGenerationTimestamp When broker generated the response (epoch millis)
38+
*/
39+
public BrokerPerformanceMetrics(final Long brokerRequestReceivedTimestamp,
40+
final Long brokerResponseGenerationTimestamp) {
41+
this.brokerRequestReceivedTimestamp = brokerRequestReceivedTimestamp;
42+
this.brokerResponseGenerationTimestamp = brokerResponseGenerationTimestamp;
43+
this.brokerHandlingTime = brokerResponseGenerationTimestamp - brokerRequestReceivedTimestamp;
44+
this.responseLatency = System.currentTimeMillis() - brokerResponseGenerationTimestamp;
45+
}
46+
47+
public Long getBrokerHandlingTime() {
48+
return brokerHandlingTime;
49+
}
50+
51+
public Long getBrokerRequestReceivedTimestamp() {
52+
return brokerRequestReceivedTimestamp;
53+
}
54+
55+
public Long getBrokerResponseGenerationTimestamp() {
56+
return brokerResponseGenerationTimestamp;
57+
}
58+
59+
public Long getResponseLatency() {
60+
return responseLatency;
61+
}
62+
63+
@Override
64+
public String toString() {
65+
return "BrokerPerformanceMetrics{" +
66+
"brokerHandlingTime=" + brokerHandlingTime +
67+
", responseLatency=" + responseLatency +
68+
", brokerRequestReceivedTimestamp=" + brokerRequestReceivedTimestamp ;
69+
}
70+
}

common4j/src/main/com/microsoft/identity/common/java/exception/BaseException.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// THE SOFTWARE.
2323
package com.microsoft.identity.common.java.exception;
2424

25+
import com.microsoft.identity.common.java.broker.BrokerPerformanceMetrics;
2526
import com.microsoft.identity.common.java.telemetry.ITelemetryAccessor;
2627
import com.microsoft.identity.common.java.telemetry.Telemetry;
2728
import com.microsoft.identity.common.java.telemetry.events.ErrorEvent;
@@ -79,6 +80,8 @@ public class BaseException extends Exception implements IErrorInformation, ITele
7980

8081
private final List<Map<String, String>> mTelemetry = new ArrayList<>();
8182

83+
private BrokerPerformanceMetrics brokerPerformanceMetrics;
84+
8285
/**
8386
* {@link Exception#addSuppressed(Throwable)} requires API19 in Android, so we're creating our own.
8487
*/
@@ -216,6 +219,15 @@ public String getUsername() {
216219
return mUsername;
217220
}
218221

222+
public void setBrokerPerformanceMetrics(final BrokerPerformanceMetrics brokerPerformanceMetrics) {
223+
this.brokerPerformanceMetrics = brokerPerformanceMetrics;
224+
}
225+
226+
@Nullable
227+
public BrokerPerformanceMetrics getBrokerPerformanceMetrics() {
228+
return brokerPerformanceMetrics;
229+
}
230+
219231
public void setUsername(@Nullable final String username) {
220232
this.mUsername = username;
221233
}

common4j/src/main/com/microsoft/identity/common/java/result/AcquireTokenResult.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@
2323
package com.microsoft.identity.common.java.result;
2424

2525
import com.microsoft.identity.common.java.WarningType;
26+
import com.microsoft.identity.common.java.broker.BrokerPerformanceMetrics;
2627
import com.microsoft.identity.common.java.providers.oauth2.TokenResult;
2728
import com.microsoft.identity.common.java.providers.oauth2.AuthorizationResult;
2829
import com.microsoft.identity.common.java.result.ILocalAuthenticationResult;
2930

31+
import javax.annotation.Nonnull;
32+
import javax.annotation.Nullable;
33+
3034
public class AcquireTokenResult {
3135

3236
private ILocalAuthenticationResult mLocalAuthenticationResult;
@@ -37,6 +41,8 @@ public class AcquireTokenResult {
3741

3842
private Boolean mSucceeded = false;
3943

44+
private BrokerPerformanceMetrics mBrokerPerformanceMetrics;
45+
4046
public void setLocalAuthenticationResult(ILocalAuthenticationResult result) {
4147
this.mLocalAuthenticationResult = result;
4248
this.mSucceeded = true;
@@ -54,6 +60,15 @@ public void setTokenResult(TokenResult tokenResult) {
5460
this.mTokenResult = tokenResult;
5561
}
5662

63+
public void setBrokerPerformanceMetrics(@Nonnull BrokerPerformanceMetrics mBrokerPerformanceMetrics) {
64+
this.mBrokerPerformanceMetrics = mBrokerPerformanceMetrics;
65+
}
66+
67+
@Nullable
68+
public BrokerPerformanceMetrics getBrokerPerformanceMetrics() {
69+
return mBrokerPerformanceMetrics;
70+
}
71+
5772
// Suppressing rawtype warnings due to the generic type AuthorizationResult
5873
@SuppressWarnings(WarningType.rawtype_warning)
5974
public AuthorizationResult getAuthorizationResult() {

0 commit comments

Comments
 (0)