Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public NetworkRequestMetricBuilder setCustomAttributes(Map<String, String> attri
* point depending upon the current {@link PerfSession} verbosity.
*
* @see GaugeManager#collectGaugeMetricOnce(Timer)
* @see PerfSession#isGaugeAndEventCollectionEnabled()
* @see PerfSession#isVerbose()
*/
public NetworkRequestMetricBuilder setRequestStartTimeMicros(long time) {
SessionManager sessionManager = SessionManager.getInstance();
Expand All @@ -234,7 +234,7 @@ public NetworkRequestMetricBuilder setRequestStartTimeMicros(long time) {
builder.setClientStartTimeUs(time);
updateSession(perfSession);

if (perfSession.isGaugeAndEventCollectionEnabled()) {
if (perfSession.isVerbose()) {
gaugeManager.collectGaugeMetricOnce(perfSession.getTimer());
}

Expand Down Expand Up @@ -265,12 +265,12 @@ public long getTimeToResponseInitiatedMicros() {
* point depending upon the current {@link PerfSession} Verbosity.
*
* @see GaugeManager#collectGaugeMetricOnce(Timer)
* @see PerfSession#isGaugeAndEventCollectionEnabled()
* @see PerfSession#isVerbose()
*/
public NetworkRequestMetricBuilder setTimeToResponseCompletedMicros(long time) {
builder.setTimeToResponseCompletedUs(time);

if (SessionManager.getInstance().perfSession().isGaugeAndEventCollectionEnabled()) {
if (SessionManager.getInstance().perfSession().isVerbose()) {
gaugeManager.collectGaugeMetricOnce(SessionManager.getInstance().perfSession().getTimer());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public void start() {

updateSession(perfSession);

if (perfSession.isGaugeAndEventCollectionEnabled()) {
if (perfSession.isVerbose()) {
gaugeManager.collectGaugeMetricOnce(perfSession.getTimer());
}
}
Expand All @@ -259,7 +259,7 @@ public void stop() {
if (!name.isEmpty()) {
transportManager.log(new TraceMetricBuilder(this).build(), getAppState());

if (SessionManager.getInstance().perfSession().isGaugeAndEventCollectionEnabled()) {
if (SessionManager.getInstance().perfSession().isVerbose()) {
gaugeManager.collectGaugeMetricOnce(
SessionManager.getInstance().perfSession().getTimer());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,15 @@ public static PerfSession createWithId(@Nullable String aqsSessionId) {
if (sessionId == null) {
sessionId = FirebaseSessionsHelperKt.createLegacySessionId();
}
PerfSession session = new PerfSession(sessionId, new Clock());
session.setGaugeAndEventCollectionEnabled(session.shouldCollectGaugesAndEvents());
return session;
return new PerfSession(sessionId, new Clock());
}

/** Creates a PerfSession with the provided {@code sessionId} and {@code clock}. */
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public PerfSession(String sessionId, Clock clock) {
this.sessionId = sessionId;
creationTime = clock.getTime();
isGaugeAndEventCollectionEnabled = shouldCollectGaugesAndEvents();
}

private PerfSession(@NonNull Parcel in) {
Expand All @@ -72,20 +71,6 @@ public Timer getTimer() {
return creationTime;
}

/*
* Enables/Disables the gauge and event collection for the system.
*/
public void setGaugeAndEventCollectionEnabled(boolean enabled) {
isGaugeAndEventCollectionEnabled = enabled;
}

/*
* Returns if gauge and event collection is enabled for the system.
*/
public boolean isGaugeAndEventCollectionEnabled() {
return isGaugeAndEventCollectionEnabled;
}

/** Returns if the current session is verbose or not. */
public boolean isVerbose() {
return isGaugeAndEventCollectionEnabled;
Expand Down Expand Up @@ -152,13 +137,22 @@ public static com.google.firebase.perf.v1.PerfSession[] buildAndSort(
}

/** If true, Session Gauge collection is enabled. */
@VisibleForTesting
public boolean shouldCollectGaugesAndEvents() {
ConfigResolver configResolver = ConfigResolver.getInstance();
return configResolver.isPerformanceMonitoringEnabled()
&& (Math.abs(this.sessionId.hashCode() % 100)
< configResolver.getSessionsSamplingRate() * 100);
}

/*
* Enables/Disables whether the session is verbose or not.
*/
@VisibleForTesting
public void setGaugeAndEventCollectionEnabled(boolean enabled) {
isGaugeAndEventCollectionEnabled = enabled;
}

/**
* Describes the kinds of special objects contained in this Parcelable's marshalled
* representation. Please refer to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@
import android.content.Context;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;
import com.google.firebase.perf.application.AppStateMonitor;
import com.google.firebase.perf.logging.FirebaseSessionsEnforcementCheck;
import com.google.firebase.perf.session.gauges.GaugeManager;
import com.google.firebase.perf.v1.ApplicationProcessState;
import com.google.firebase.perf.v1.GaugeMetadata;
import com.google.firebase.perf.v1.GaugeMetric;
import java.lang.ref.WeakReference;
Expand All @@ -37,7 +35,6 @@ public class SessionManager {
private static final SessionManager instance = new SessionManager();

private final GaugeManager gaugeManager;
private final AppStateMonitor appStateMonitor;
private final Set<WeakReference<SessionAwareObject>> clients = new HashSet<>();

private PerfSession perfSession;
Expand All @@ -49,23 +46,20 @@ public static SessionManager getInstance() {

/** Returns the currently active PerfSession. */
public final PerfSession perfSession() {
FirebaseSessionsEnforcementCheck.checkSession(
perfSession, "Access perf session from manger without aqs ready");
FirebaseSessionsEnforcementCheck.checkSession(perfSession, "PerfSession.perfSession()");

return perfSession;
}

private SessionManager() {
// session should quickly updated by session subscriber.
this(GaugeManager.getInstance(), PerfSession.createWithId(null), AppStateMonitor.getInstance());
this(GaugeManager.getInstance(), PerfSession.createWithId(null));
}

@VisibleForTesting
public SessionManager(
GaugeManager gaugeManager, PerfSession perfSession, AppStateMonitor appStateMonitor) {
public SessionManager(GaugeManager gaugeManager, PerfSession perfSession) {
this.gaugeManager = gaugeManager;
this.perfSession = perfSession;
this.appStateMonitor = appStateMonitor;
}

/**
Expand All @@ -83,8 +77,7 @@ public void setApplicationContext(final Context appContext) {
*/
public void stopGaugeCollectionIfSessionRunningTooLong() {
FirebaseSessionsEnforcementCheck.checkSession(
perfSession,
"Session is not ready while trying to stopGaugeCollectionIfSessionRunningTooLong");
perfSession, "SessionManager.stopGaugeCollectionIfSessionRunningTooLong");

if (perfSession.isSessionRunningTooLong()) {
gaugeManager.stopCollectingGauges();
Expand Down Expand Up @@ -123,7 +116,7 @@ public void updatePerfSession(PerfSession perfSession) {
}

// Start of stop the gauge data collection.
startOrStopCollectingGauges(appStateMonitor.getAppState());
startOrStopCollectingGauges();
}

/**
Expand All @@ -133,7 +126,7 @@ public void updatePerfSession(PerfSession perfSession) {
* this does not reset the perfSession.
*/
public void initializeGaugeCollection() {
startOrStopCollectingGauges(ApplicationProcessState.FOREGROUND);
startOrStopCollectingGauges();
}

/**
Expand All @@ -160,12 +153,11 @@ public void unregisterForSessionUpdates(WeakReference<SessionAwareObject> client
}
}

private void startOrStopCollectingGauges(ApplicationProcessState appState) {
FirebaseSessionsEnforcementCheck.checkSession(
perfSession, "Session is not ready while trying to startOrStopCollectingGauges");
private void startOrStopCollectingGauges() {
FirebaseSessionsEnforcementCheck.checkSession(perfSession, "startOrStopCollectingGauges");

if (perfSession.isGaugeAndEventCollectionEnabled()) {
gaugeManager.startCollectingGauges(perfSession, appState);
if (perfSession.isVerbose()) {
gaugeManager.startCollectingGauges(perfSession);
} else {
gaugeManager.stopCollectingGauges();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class CpuGaugeCollector {
private final String procFileName;
private final long clockTicksPerSecond;

@Nullable private ScheduledFuture cpuMetricCollectorJob = null;
@Nullable private ScheduledFuture<?> cpuMetricCollectorJob = null;
private long cpuMetricCollectionRateMs = UNSET_CPU_METRIC_COLLECTION_RATE;

// TODO(b/258263016): Migrate to go/firebase-android-executors
Expand Down Expand Up @@ -166,6 +166,7 @@ private synchronized void scheduleCpuMetricCollectionWithRate(
CpuMetricReading currCpuReading = syncCollectCpuMetric(referenceTime);
if (currCpuReading != null) {
cpuMetricReadings.add(currCpuReading);
GaugeCounter.Companion.getInstance().incrementCounter();
}
},
/* initialDelay */ 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.firebase.perf.session.gauges

import java.util.concurrent.atomic.AtomicInteger

/**
* [GaugeCounter] is a threadsafe counter for gauge metrics. If the metrics count exceeds
* [MAX_METRIC_COUNT], it attempts to log the metrics to Firelog.
*/
class GaugeCounter private constructor() {
private val counter = AtomicInteger(0)
private val gaugeManager: GaugeManager = GaugeManager.getInstance()

fun incrementCounter() {
val metricsCount = counter.incrementAndGet()

if (metricsCount >= MAX_METRIC_COUNT) {
gaugeManager.logGaugeMetrics()
}
}

fun decrementCounter() {
counter.decrementAndGet()
}

companion object {
val instance: GaugeCounter by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { GaugeCounter() }
const val MAX_METRIC_COUNT = 25
}
}
Loading
Loading