Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,16 @@ public static final class Broker {
* Value for nativebroker mode sent in the extra query param by ESTS when the request is from lookup.
*/
public static final String LOOKUP_MODE_VALUE = "Lookup";

/**
* Bundle key for the broker telemetry request payload.
*/
public static final String BROKER_TELEMETRY_REQUEST = "broker_telemetry_request";

/**
* Bundle key for the broker telemetry schema payload.
*/
public static final String BROKER_TELEMETRY_SCHEMA = "broker_telemetry_schema";
}

@NoArgsConstructor(access = AccessLevel.PRIVATE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

import java.time.Instant
import java.util.concurrent.CopyOnWriteArrayList

/**
* Thread-safe accumulator of [ExecutionEvent] instances for a single authentication request.
*
* Call [addEvent] from any thread to record a phase transition. Call [toTelemetrySchema] when
* the request is complete to produce a [TelemetrySchema] with the full event timeline.
*
* @param correlationId Correlation ID for the authentication request being tracked.
*/
class EventCollector(private val correlationId: String) {
private val events = CopyOnWriteArrayList<ExecutionEvent>()
private val startTimeMs: Long = System.currentTimeMillis()

/**
* Records a new [ExecutionEvent] with the elapsed time since collection started.
* The resulting [ExecutionEvent.timestampMs] is relative elapsed milliseconds from
* collector start — not an absolute epoch timestamp.
*
* @param tag The [EventTag] identifying the phase.
* @param diagnosticCode Optional diagnostic code for additional context.
* @param errorCode Optional error code if this event marks a failure condition.
*/
fun addEvent(tag: EventTag, diagnosticCode: Int? = null, errorCode: Int? = null) {
events.add(
ExecutionEvent(
tag = tag,
timestampMs = System.currentTimeMillis() - startTimeMs,
diagnosticCode = diagnosticCode,
errorCode = errorCode
)
)
}

/**
* Builds a [TelemetrySchema] from all events collected so far.
*
* @return A [TelemetrySchema] containing a [PerformanceRecord] with the full event timeline.
*/
fun toTelemetrySchema(): TelemetrySchema {
val duration = System.currentTimeMillis() - startTimeMs
return TelemetrySchema(
correlationId = correlationId,
performanceRecord = PerformanceRecord(
startTime = Instant.ofEpochMilli(startTimeMs).toString(),
duration = duration,
executionFlow = events.toList()
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

import com.google.gson.annotations.SerializedName

/**
* Enum of event tags representing distinct phases in the broker authentication flow.
* Each tag has a compact serialized value for efficient IPC transport.
*
* @param value Compact serialized form used in JSON (e.g., "bre.recv" for BrokerRequestReceived).
* Prefix convention: bre=BrokerEntry, bdi=BrokerDispatch, bca=BrokerCache,
* bne=BrokerNetwork, brs=BrokerResponse, cst=CommonStrategy.
*/
enum class EventTag(@SerializedName("v") val value: String) {
// BrokerEntry (5)
BrokerRequestReceived("bre.recv"),
BrokerRequestDeserialized("bre.dser"),
BrokerAccountLookupStart("bre.als"),
BrokerAccountLookupEnd("bre.ale"),
BrokerRequestValidated("bre.val"),
// BrokerDispatch (3)
BrokerControllerSelected("bdi.csel"),
BrokerCommandQueued("bdi.cq"),
BrokerCommandExecutionStart("bdi.cex"),
// BrokerCache (6)
BrokerCacheCheckStart("bca.cks"),
BrokerCacheCheckEnd("bca.cke"),
BrokerCacheHit("bca.hit"),
BrokerCacheMiss("bca.miss"),
BrokerCacheWriteStart("bca.wrs"),
BrokerCacheWriteEnd("bca.wre"),
// BrokerNetwork (5)
BrokerPrtLoadStart("bne.prt"),
BrokerNetworkCallStart("bne.ncs"),
BrokerNetworkCallEnd("bne.nce"),
BrokerTokenAcquired("bne.tok"),
BrokerNetworkCallFailed("bne.nfl"),
// BrokerResponse (3)
BrokerResponseSerialized("brs.ser"),
BrokerResponseSent("brs.snt"),
BrokerRequestFailed("brs.fail"),
// CommonStrategy (2)
CommonHttpRequestExecute("cst.hreq"),
CommonHttpResponseReceived("cst.hrsp")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

import com.google.gson.annotations.SerializedName

/**
* Represents a single timed event captured during a broker authentication flow.
*
* @param tag The [EventTag] identifying the phase of the authentication flow.
* @param timestampMs Elapsed milliseconds since the start of the [EventCollector].
* @param threadId The ID of the thread that recorded this event.
* @param diagnosticCode Optional diagnostic code for additional context.
* @param errorCode Optional error code if this event marks a failure condition.
*/
data class ExecutionEvent(
@SerializedName("t") val tag: EventTag,
@SerializedName("ts") val timestampMs: Long,
@SerializedName("tid") val threadId: Long = Thread.currentThread().id,
@SerializedName("d") val diagnosticCode: Int? = null,
@SerializedName("e") val errorCode: Int? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

/**
* Implemented by classes that carry a [TelemetrySchema] instance, enabling structured
* per-request performance data to flow from the broker through the authentication result chain.
*/
interface ITelemetrySchemaProvider {
var telemetrySchema: TelemetrySchema?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

import com.google.gson.annotations.SerializedName

/**
* Container aggregating timing data for a single authentication request.
*
* @param version Schema version of this record (defaults to "1.0.0").
* @param startTime ISO 8601 UTC timestamp when the request was initiated.
* @param duration Total elapsed time in milliseconds from start to completion.
* @param executionFlow Ordered list of [ExecutionEvent] entries captured during the flow.
*/
data class PerformanceRecord(
@SerializedName("version") val version: String = "1.0.0",
@SerializedName("start_time") val startTime: String,
@SerializedName("duration") val duration: Long,
@SerializedName("execution_flow") val executionFlow: List<ExecutionEvent>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

/**
* Null-safe utility for recording telemetry events via an optional [EventCollector].
*
* All methods are no-ops when [collector] is null, so callers do not need to perform null checks.
*/
object TelemetryHelper {
/**
* Safely adds an event to [collector] if it is non-null.
*
* @param collector The [EventCollector] to record into, or null to skip recording.
* @param tag The [EventTag] identifying the phase.
* @param diagnosticCode Optional diagnostic code for additional context.
* @param errorCode Optional error code if this event marks a failure condition.
*/
@JvmStatic
fun addEventSafely(
collector: EventCollector?,
tag: EventTag,
diagnosticCode: Int? = null,
errorCode: Int? = null
) {
collector?.addEvent(tag, diagnosticCode, errorCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.java.broker.telemetry

import com.google.gson.annotations.SerializedName

/**
* Top-level telemetry schema emitted by the broker for each authentication request.
* Carries structured timing, outcome, and policy metadata that client SDKs can surface
* as per-request performance breakdowns.
*
* @param schemaVersion Version of this schema (defaults to [CURRENT_VERSION]).
* @param correlationId Correlation ID linking this schema to the authentication request.
* @param name Optional descriptive name for the operation.
* @param version Optional version of the operation.
* @param authOutcome Optional outcome of the authentication flow (e.g., "success", "failure").
* @param errorCode Optional error code when authentication fails.
* @param responseStarvationDuration Optional duration (ms) the response was starved before processing.
* @param powerPolicy Optional flag indicating whether a power policy was active.
* @param deviceIdle Optional flag indicating whether the device was idle during the flow.
* @param performanceRecord Optional [PerformanceRecord] containing the detailed event timeline.
*/
data class TelemetrySchema(
@SerializedName("schema_version") val schemaVersion: String = CURRENT_VERSION,
@SerializedName("correlation_id") val correlationId: String,
@SerializedName("name") val name: String? = null,
@SerializedName("version") val version: String? = null,
@SerializedName("auth_outcome") val authOutcome: String? = null,
@SerializedName("error_code") val errorCode: String? = null,
@SerializedName("response_starvation_duration") val responseStarvationDuration: Int? = null,
@SerializedName("power_policy") val powerPolicy: Boolean? = null,
@SerializedName("device_idle") val deviceIdle: Boolean? = null,
@SerializedName("perf") val performanceRecord: PerformanceRecord? = null
) {
companion object {
const val CURRENT_VERSION = "1.0.0"
const val MIN_SUPPORTED_MAJOR = 1
}
}
Loading
Loading