diff --git a/library/src/main/java/com/bumptech/glide/Glide.java b/library/src/main/java/com/bumptech/glide/Glide.java index 89b950cd8f..13fa8b5b7a 100644 --- a/library/src/main/java/com/bumptech/glide/Glide.java +++ b/library/src/main/java/com/bumptech/glide/Glide.java @@ -322,7 +322,8 @@ private static void throwIncorrectGlideModule(Exception e) { int logLevel, @NonNull RequestOptions defaultRequestOptions, @NonNull Map, TransitionOptions> defaultTransitionOptions, - @NonNull List> defaultRequestListeners) { + @NonNull List> defaultRequestListeners, + boolean isLoggingRequestOriginsEnabled) { this.engine = engine; this.bitmapPool = bitmapPool; this.arrayPool = arrayPool; @@ -522,6 +523,7 @@ Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitm defaultTransitionOptions, defaultRequestListeners, engine, + isLoggingRequestOriginsEnabled, logLevel); } diff --git a/library/src/main/java/com/bumptech/glide/GlideBuilder.java b/library/src/main/java/com/bumptech/glide/GlideBuilder.java index 55f60f0fc8..98338cfcd3 100644 --- a/library/src/main/java/com/bumptech/glide/GlideBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GlideBuilder.java @@ -55,6 +55,7 @@ public final class GlideBuilder { private boolean isActiveResourceRetentionAllowed; @Nullable private List> defaultRequestListeners; + private boolean isLoggingRequestOriginsEnabled; /** * Sets the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} implementation to use @@ -407,6 +408,21 @@ public GlideBuilder addGlobalRequestListener(@NonNull RequestListener li return this; } + /** + * Set to {@code true} to make Glide populate + * {@link com.bumptech.glide.load.engine.GlideException#setOrigin(Exception)} for failed requests. + * + *

The exception set by this method is not printed by {@link GlideException} and can only be + * viewed via a {@link RequestListener} that reads the field via + * {@link GlideException#getOrigin()}. + * + *

This is an experimental API that may be removed in the future. + */ + public GlideBuilder setLogRequestOrigins(boolean isEnabled) { + isLoggingRequestOriginsEnabled = isEnabled; + return this; + } + void setRequestManagerFactory(@Nullable RequestManagerFactory factory) { this.requestManagerFactory = factory; } @@ -492,6 +508,7 @@ Glide build(@NonNull Context context) { logLevel, defaultRequestOptions.lock(), defaultTransitionOptions, - defaultRequestListeners); + defaultRequestListeners, + isLoggingRequestOriginsEnabled); } } diff --git a/library/src/main/java/com/bumptech/glide/GlideContext.java b/library/src/main/java/com/bumptech/glide/GlideContext.java index a587b19bd4..71ad97a36a 100644 --- a/library/src/main/java/com/bumptech/glide/GlideContext.java +++ b/library/src/main/java/com/bumptech/glide/GlideContext.java @@ -33,6 +33,7 @@ public class GlideContext extends ContextWrapper { private final List> defaultRequestListeners; private final Map, TransitionOptions> defaultTransitionOptions; private final Engine engine; + private boolean isLoggingRequestOriginsEnabled; private final int logLevel; public GlideContext( @@ -44,6 +45,7 @@ public GlideContext( @NonNull Map, TransitionOptions> defaultTransitionOptions, @NonNull List> defaultRequestListeners, @NonNull Engine engine, + boolean isLoggingRequestOriginsEnabled, int logLevel) { super(context.getApplicationContext()); this.arrayPool = arrayPool; @@ -53,6 +55,7 @@ public GlideContext( this.defaultRequestListeners = defaultRequestListeners; this.defaultTransitionOptions = defaultTransitionOptions; this.engine = engine; + this.isLoggingRequestOriginsEnabled = isLoggingRequestOriginsEnabled; this.logLevel = logLevel; mainHandler = new Handler(Looper.getMainLooper()); @@ -112,4 +115,14 @@ public int getLogLevel() { public ArrayPool getArrayPool() { return arrayPool; } + + /** + * Returns {@code true} if Glide should populate + * {@link com.bumptech.glide.load.engine.GlideException#setOrigin(Exception)} for failed requests. + * + *

This is an experimental API that may be removed in the future. + */ + public boolean isLoggingRequestOriginsEnabled() { + return isLoggingRequestOriginsEnabled; + } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/GlideException.java b/library/src/main/java/com/bumptech/glide/load/engine/GlideException.java index 79d05eff54..f74488b3ef 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/GlideException.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/GlideException.java @@ -27,6 +27,8 @@ public final class GlideException extends Exception { private DataSource dataSource; private Class dataClass; private String detailMessage; + @Nullable + private Exception exception; public GlideException(String message) { this(message, Collections.emptyList()); @@ -52,7 +54,25 @@ void setLoggingDetails(Key key, DataSource dataSource, Class dataClass) { this.dataClass = dataClass; } + /** + * Sets a stack trace that includes where the request originated. + * + *

This is an experimental API that may be removed in the future. + */ + public void setOrigin(@Nullable Exception exception) { + this.exception = exception; + } + /** + * Returns an {@link Exception} with a stack trace that includes where the request originated + * (if previously set via {@link #setOrigin(Exception)}) + * + *

This is an experimental API that may be removed in the future. + */ + @Nullable + public Exception getOrigin() { + return exception; + } // No need to synchronize when doing nothing whatsoever. @SuppressWarnings("UnsynchronizedOverridesSynchronized") diff --git a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java index 7207bc57e5..27dd340984 100644 --- a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java +++ b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java @@ -108,6 +108,8 @@ private enum Status { private Drawable fallbackDrawable; private int width; private int height; + @Nullable + private RuntimeException requestOrigin; public static SingleRequest obtain( Context context, @@ -183,6 +185,10 @@ private void init( this.engine = engine; this.animationFactory = animationFactory; status = Status.PENDING; + + if (glideContext.isLoggingRequestOriginsEnabled()) { + requestOrigin = new RuntimeException("Glide request origin trace"); + } } @NonNull @@ -212,6 +218,7 @@ public void recycle() { fallbackDrawable = null; width = -1; height = -1; + requestOrigin = null; POOL.release(this); } @@ -584,6 +591,7 @@ public void onLoadFailed(GlideException e) { private void onLoadFailed(GlideException e, int maxLogLevel) { stateVerifier.throwIfRecycled(); + e.setOrigin(requestOrigin); int logLevel = glideContext.getLogLevel(); if (logLevel <= maxLogLevel) { Log.w(GLIDE_TAG, "Load failed for " + model + " with size [" + width + "x" + height + "]", e); diff --git a/library/test/src/test/java/com/bumptech/glide/GlideContextTest.java b/library/test/src/test/java/com/bumptech/glide/GlideContextTest.java index 34dc8de84f..41e8201fb5 100644 --- a/library/test/src/test/java/com/bumptech/glide/GlideContextTest.java +++ b/library/test/src/test/java/com/bumptech/glide/GlideContextTest.java @@ -45,6 +45,7 @@ public void setUp() { transitionOptions, /*defaultRequestListeners=*/ Collections.>emptyList(), mock(Engine.class), + /*isLoggingRequestOriginsEnabled=*/ false, Log.DEBUG); }