Improve logging

- Make sure logging of UnknownHostException indicates the failure reason
- Indent stack traces inside event blocks in EventLogger
- Don't log media URLs

PiperOrigin-RevId: 302007601
This commit is contained in:
olly 2020-03-20 12:17:32 +00:00 committed by Oliver Woodman
parent c0d632936a
commit 429bdfb974
5 changed files with 83 additions and 48 deletions

View File

@ -223,7 +223,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
responseByteStream = responseBody.byteStream();
} catch (IOException e) {
throw new HttpDataSourceException(
"Unable to connect to " + dataSpec.uri, e, dataSpec, HttpDataSourceException.TYPE_OPEN);
"Unable to connect", e, dataSpec, HttpDataSourceException.TYPE_OPEN);
}
int responseCode = response.code();

View File

@ -21,6 +21,7 @@ import androidx.annotation.Nullable;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.UnknownHostException;
/** Wrapper around {@link android.util.Log} which allows to set the log level. */
public final class Log {
@ -69,7 +70,8 @@ public final class Log {
}
/**
* Sets whether stack traces of {@link Throwable}s will be logged to logcat.
* Sets whether stack traces of {@link Throwable}s will be logged to logcat. Stack trace logging
* is enabled by default.
*
* @param logStackTraces Whether stack traces will be logged.
*/
@ -86,11 +88,7 @@ public final class Log {
/** @see android.util.Log#d(String, String, Throwable) */
public static void d(String tag, String message, @Nullable Throwable throwable) {
if (!logStackTraces) {
d(tag, appendThrowableMessage(message, throwable));
} else if (logLevel == LOG_LEVEL_ALL) {
android.util.Log.d(tag, message, throwable);
}
d(tag, appendThrowableString(message, throwable));
}
/** @see android.util.Log#i(String, String) */
@ -102,11 +100,7 @@ public final class Log {
/** @see android.util.Log#i(String, String, Throwable) */
public static void i(String tag, String message, @Nullable Throwable throwable) {
if (!logStackTraces) {
i(tag, appendThrowableMessage(message, throwable));
} else if (logLevel <= LOG_LEVEL_INFO) {
android.util.Log.i(tag, message, throwable);
}
i(tag, appendThrowableString(message, throwable));
}
/** @see android.util.Log#w(String, String) */
@ -118,11 +112,7 @@ public final class Log {
/** @see android.util.Log#w(String, String, Throwable) */
public static void w(String tag, String message, @Nullable Throwable throwable) {
if (!logStackTraces) {
w(tag, appendThrowableMessage(message, throwable));
} else if (logLevel <= LOG_LEVEL_WARNING) {
android.util.Log.w(tag, message, throwable);
}
w(tag, appendThrowableString(message, throwable));
}
/** @see android.util.Log#e(String, String) */
@ -134,18 +124,54 @@ public final class Log {
/** @see android.util.Log#e(String, String, Throwable) */
public static void e(String tag, String message, @Nullable Throwable throwable) {
if (!logStackTraces) {
e(tag, appendThrowableMessage(message, throwable));
} else if (logLevel <= LOG_LEVEL_ERROR) {
android.util.Log.e(tag, message, throwable);
e(tag, appendThrowableString(message, throwable));
}
/**
* Returns a string representation of a {@link Throwable} suitable for logging, taking into
* account whether {@link #setLogStackTraces(boolean)} stack trace logging} is enabled.
*
* <p>Stack trace logging may be unconditionally suppressed for some expected failure modes (e.g.,
* {@link Throwable Throwables} that are expected if the device doesn't have network connectivity)
* to avoid log spam.
*
* @param throwable The {@link Throwable}.
* @return The string representation of the {@link Throwable}.
*/
@Nullable
public static String getThrowableString(@Nullable Throwable throwable) {
if (throwable == null) {
return null;
} else if (isCausedByUnknownHostException(throwable)) {
// UnknownHostException implies the device doesn't have network connectivity.
// UnknownHostException.getMessage() may return a string that's more verbose than desired for
// logging an expected failure mode. Conversely, android.util.Log.getStackTraceString has
// special handling to return the empty string, which can result in logging that doesn't
// indicate the failure mode at all. Hence we special case this exception to always return a
// concise but useful message.
return "UnknownHostException (no network)";
} else if (!logStackTraces) {
return throwable.getMessage();
} else {
return android.util.Log.getStackTraceString(throwable).trim().replace("\t", " ");
}
}
private static String appendThrowableMessage(String message, @Nullable Throwable throwable) {
if (throwable == null) {
private static String appendThrowableString(String message, @Nullable Throwable throwable) {
@Nullable String throwableString = getThrowableString(throwable);
if (!TextUtils.isEmpty(throwableString)) {
message += "\n " + throwableString.replace("\n", "\n ") + '\n';
}
return message;
}
String throwableMessage = throwable.getMessage();
return TextUtils.isEmpty(throwableMessage) ? message : message + " - " + throwableMessage;
private static boolean isCausedByUnknownHostException(@Nullable Throwable throwable) {
while (throwable != null) {
if (throwable instanceof UnknownHostException) {
return true;
}
throwable = throwable.getCause();
}
return false;
}
}

View File

@ -477,7 +477,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
playbackInfo = playbackInfo.copyWithPlaybackError(e);
maybeNotifyPlaybackInfoChanged();
} catch (IOException e) {
Log.e(TAG, "Source error.", e);
Log.e(TAG, "Source error", e);
stopInternal(
/* forceResetRenderers= */ false,
/* resetPositionAndState= */ false,
@ -485,7 +485,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
playbackInfo = playbackInfo.copyWithPlaybackError(ExoPlaybackException.createForSource(e));
maybeNotifyPlaybackInfoChanged();
} catch (RuntimeException | OutOfMemoryError e) {
Log.e(TAG, "Internal runtime error.", e);
Log.e(TAG, "Internal runtime error", e);
ExoPlaybackException error =
e instanceof OutOfMemoryError
? ExoPlaybackException.createForOutOfMemoryError((OutOfMemoryError) e)

View File

@ -279,8 +279,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
try {
connection = makeConnection(dataSpec);
} catch (IOException e) {
throw new HttpDataSourceException("Unable to connect to " + dataSpec.uri.toString(), e,
dataSpec, HttpDataSourceException.TYPE_OPEN);
throw new HttpDataSourceException(
"Unable to connect", e, dataSpec, HttpDataSourceException.TYPE_OPEN);
}
String responseMessage;
@ -289,8 +289,8 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
responseMessage = connection.getResponseMessage();
} catch (IOException e) {
closeConnectionQuietly();
throw new HttpDataSourceException("Unable to connect to " + dataSpec.uri.toString(), e,
dataSpec, HttpDataSourceException.TYPE_OPEN);
throw new HttpDataSourceException(
"Unable to connect", e, dataSpec, HttpDataSourceException.TYPE_OPEN);
}
// Check for a valid response code.

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.util;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.Surface;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
@ -209,7 +210,7 @@ public class EventLogger implements AnalyticsListener {
logd(eventTime, "tracks", "[]");
return;
}
logd("tracks [" + getEventTimeString(eventTime) + ", ");
logd("tracks [" + getEventTimeString(eventTime));
// Log tracks associated to renderers.
int rendererCount = mappedTrackInfo.getRendererCount();
for (int rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
@ -293,7 +294,7 @@ public class EventLogger implements AnalyticsListener {
@Override
public void onMetadata(EventTime eventTime, Metadata metadata) {
logd("metadata [" + getEventTimeString(eventTime) + ", ");
logd("metadata [" + getEventTimeString(eventTime));
printMetadata(metadata, " ");
logd("]");
}
@ -485,27 +486,26 @@ public class EventLogger implements AnalyticsListener {
}
/**
* Logs an error message and exception.
* Logs an error message.
*
* @param msg The message to log.
* @param tr The exception to log.
*/
protected void loge(String msg, @Nullable Throwable tr) {
Log.e(tag, msg, tr);
protected void loge(String msg) {
Log.e(tag, msg);
}
// Internal methods
private void logd(EventTime eventTime, String eventName) {
logd(getEventString(eventTime, eventName));
logd(getEventString(eventTime, eventName, /* eventDescription= */ null, /* throwable= */ null));
}
private void logd(EventTime eventTime, String eventName, String eventDescription) {
logd(getEventString(eventTime, eventName, eventDescription));
logd(getEventString(eventTime, eventName, eventDescription, /* throwable= */ null));
}
private void loge(EventTime eventTime, String eventName, @Nullable Throwable throwable) {
loge(getEventString(eventTime, eventName), throwable);
loge(getEventString(eventTime, eventName, /* eventDescription= */ null, throwable));
}
private void loge(
@ -513,7 +513,7 @@ public class EventLogger implements AnalyticsListener {
String eventName,
String eventDescription,
@Nullable Throwable throwable) {
loge(getEventString(eventTime, eventName, eventDescription), throwable);
loge(getEventString(eventTime, eventName, eventDescription, throwable));
}
private void printInternalError(EventTime eventTime, String type, Exception e) {
@ -526,12 +526,21 @@ public class EventLogger implements AnalyticsListener {
}
}
private String getEventString(EventTime eventTime, String eventName) {
return eventName + " [" + getEventTimeString(eventTime) + "]";
private String getEventString(
EventTime eventTime,
String eventName,
@Nullable String eventDescription,
@Nullable Throwable throwable) {
String eventString = eventName + " [" + getEventTimeString(eventTime);
if (eventDescription != null) {
eventString += ", " + eventDescription;
}
private String getEventString(EventTime eventTime, String eventName, String eventDescription) {
return eventName + " [" + getEventTimeString(eventTime) + ", " + eventDescription + "]";
@Nullable String throwableString = Log.getThrowableString(throwable);
if (!TextUtils.isEmpty(throwableString)) {
eventString += "\n " + throwableString.replace("\n", "\n ") + '\n';
}
eventString += "]";
return eventString;
}
private String getEventTimeString(EventTime eventTime) {