Limit potential size of job info debug log section.

This commit is contained in:
Greyson Parrelli
2026-07-30 09:43:18 -04:00
committed by Alex Hart
parent 30b048976c
commit dd2ee394ef
2 changed files with 29 additions and 10 deletions
@@ -44,6 +44,9 @@ class JobController {
private static final Predicate<MinimalJobSpec> NO_PREDICATE = spec -> true;
/** Max number of items we'll print for any single collection in {@link #getDebugInfo()}, to avoid OOM'ing while building the string. */
private static final int DEBUG_ITEM_LIMIT = 500;
private final Application application;
private final JobStorage jobStorage;
private final JobInstantiator jobInstantiator;
@@ -409,8 +412,8 @@ class JobController {
@WorkerThread
synchronized @NonNull String getDebugInfo() {
List<JobSpec> running = runningJobs.keySet().stream().map(jobStorage::getJobSpec).collect(Collectors.toList());
List<JobSpec> jobs = jobStorage.debugGetJobSpecs(1000);
List<ConstraintSpec> constraints = jobStorage.debugGetConstraintSpecs(1000);
List<JobSpec> jobs = jobStorage.debugGetJobSpecs(DEBUG_ITEM_LIMIT);
List<ConstraintSpec> constraints = jobStorage.debugGetConstraintSpecs(DEBUG_ITEM_LIMIT);
List<DependencySpec> dependencies = jobStorage.debugGetAllDependencySpecs();
String additional = jobStorage.debugAdditionalDetails();
@@ -443,7 +446,10 @@ class JobController {
info.append("\n-- Dependencies\n");
if (!dependencies.isEmpty()) {
dependencies.stream().forEach(d -> info.append(d.toString()).append('\n'));
dependencies.stream().limit(DEBUG_ITEM_LIMIT).forEach(d -> info.append(d.toString()).append('\n'));
if (dependencies.size() > DEBUG_ITEM_LIMIT) {
info.append("...TRUNCATED, showing first ").append(DEBUG_ITEM_LIMIT).append(" of ").append(dependencies.size()).append('\n');
}
} else {
info.append("None\n");
}
@@ -22,6 +22,9 @@ class FastJobStorage(private val jobDatabase: JobDatabase) : JobStorage {
private val TAG = Log.tag(FastJobStorage::class)
private const val JOB_CACHE_LIMIT = 1000
private const val DEBUG = false
/** Max number of items we'll print for any single collection in [debugAdditionalDetails], to avoid OOM'ing while building the string. */
private const val DEBUG_ITEM_LIMIT = 500
}
/** We keep a trimmed down version of every job in memory. */
@@ -432,13 +435,23 @@ class FastJobStorage(private val jobDatabase: JobDatabase) : JobStorage {
val nonEmptyDependencies = dependenciesByJobId.filterValues { it.isNotEmpty() }
return buildString {
appendLine("minimalJobs: Size(${minimalJobs.size}), Items(${minimalJobs.joinToString(", ") { it.toLogString() }})")
appendLine("jobSpecCache: Size(${jobSpecCache.size}), Items(${jobSpecCache.keys.joinToString(", ") { it.toLogString() }})")
appendLine("eligibleJobs: Size(${eligibleJobs.size}), Items(${eligibleJobs.joinToString(", ") { it.toLogString() }})")
appendLine("migrationJobs: Size(${migrationJobs.size}), Items(${migrationJobs.joinToString(", ") { it.toLogString() }})")
appendLine("mostEligibleForQueue: Size(${mostEligibleJobForQueue.size}), Items(${mostEligibleJobForQueue.entries.joinToString(", ") { "[${it.key} => ${it.value.toLogString()}]" }})")
appendLine("constraintsByJobId: Size(${constraintsByJobId.size}), Items(${constraintsByJobId.entries.joinToString(", ") { "[${it.key.toLogString()} => ${it.value.joinToString(", ") { c -> c.toLogString() }}]" }})")
appendLine("dependenciesByJobId: Size(${nonEmptyDependencies.size}), Items(${nonEmptyDependencies.entries.joinToString(", ") { "[${it.key.toLogString()} => ${it.value.map { d -> d.toLogString() }}]" }})")
appendLine("minimalJobs: Size(${minimalJobs.size}), Items(${minimalJobs.toTruncatedLogString { it.toLogString() }})")
appendLine("jobSpecCache: Size(${jobSpecCache.size}), Items(${jobSpecCache.keys.toTruncatedLogString { it.toLogString() }})")
appendLine("eligibleJobs: Size(${eligibleJobs.size}), Items(${eligibleJobs.toTruncatedLogString { it.toLogString() }})")
appendLine("migrationJobs: Size(${migrationJobs.size}), Items(${migrationJobs.toTruncatedLogString { it.toLogString() }})")
appendLine("mostEligibleForQueue: Size(${mostEligibleJobForQueue.size}), Items(${mostEligibleJobForQueue.entries.toTruncatedLogString { "[${it.key} => ${it.value.toLogString()}]" }})")
appendLine("constraintsByJobId: Size(${constraintsByJobId.size}), Items(${constraintsByJobId.entries.toTruncatedLogString { "[${it.key.toLogString()} => ${it.value.joinToString(", ") { c -> c.toLogString() }}]" }})")
appendLine("dependenciesByJobId: Size(${nonEmptyDependencies.size}), Items(${nonEmptyDependencies.entries.toTruncatedLogString { "[${it.key.toLogString()} => ${it.value.map { d -> d.toLogString() }}]" }})")
}
}
private fun <T> Collection<T>.toTruncatedLogString(transform: (T) -> CharSequence): String {
val rendered = this.asSequence().take(DEBUG_ITEM_LIMIT).joinToString(", ", transform = transform)
return if (this.size > DEBUG_ITEM_LIMIT) {
"$rendered, ...TRUNCATED, showing first $DEBUG_ITEM_LIMIT of ${this.size}"
} else {
rendered
}
}