/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.imagepipeline.listener; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import java.util.HashMap; import java.util.Map; import android.os.SystemClock; import android.util.Pair; import com.facebook.common.logging.FLog; import com.facebook.imagepipeline.request.ImageRequest; /** * Logging for {@link ImageRequest}s. */ public class RequestLoggingListener implements RequestListener { private static final String TAG = "RequestLoggingListener"; @GuardedBy("this") private final Map<Pair<String, String>, Long> mProducerStartTimeMap; @GuardedBy("this") private final Map<String, Long> mRequestStartTimeMap; public RequestLoggingListener() { mProducerStartTimeMap = new HashMap<>(); mRequestStartTimeMap = new HashMap<>(); } @Override public synchronized void onRequestStart( ImageRequest request, Object callerContextObject, String requestId, boolean isPrefetch) { if (FLog.isLoggable(FLog.VERBOSE)) { FLog.v( TAG, "time %d: onRequestSubmit: {requestId: %s, callerContext: %s, isPrefetch: %b}", getTime(), requestId, callerContextObject, isPrefetch); mRequestStartTimeMap.put(requestId, getTime()); } } @Override public synchronized void onProducerStart(String requestId, String producerName) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); long startTime = getTime(); mProducerStartTimeMap.put(mapKey, startTime); FLog.v( TAG, "time %d: onProducerStart: {requestId: %s, producer: %s}", startTime, requestId, producerName); } } @Override public synchronized void onProducerFinishWithSuccess( String requestId, String producerName, @Nullable Map<String, String> extraMap) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.remove(mapKey); long currentTime = getTime(); FLog.v( TAG, "time %d: onProducerFinishWithSuccess: " + "{requestId: %s, producer: %s, elapsedTime: %d ms, extraMap: %s}", currentTime, requestId, producerName, getElapsedTime(startTime, currentTime), extraMap); } } @Override public synchronized void onProducerFinishWithFailure( String requestId, String producerName, Throwable throwable, @Nullable Map<String, String> extraMap) { if (FLog.isLoggable(FLog.WARN)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.remove(mapKey); long currentTime = getTime(); FLog.w( TAG, "time %d: onProducerFinishWithFailure: " + "{requestId: %s, stage: %s, elapsedTime: %d ms, extraMap: %s, throwable: %s}", currentTime, requestId, producerName, getElapsedTime(startTime, currentTime), extraMap, throwable.toString()); } } @Override public synchronized void onProducerFinishWithCancellation( String requestId, String producerName, @Nullable Map<String, String> extraMap) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.remove(mapKey); long currentTime = getTime(); FLog.v( TAG, "time %d: onProducerFinishWithCancellation: " + "{requestId: %s, stage: %s, elapsedTime: %d ms, extraMap: %s}", currentTime, requestId, producerName, getElapsedTime(startTime, currentTime), extraMap); } } @Override public synchronized void onProducerEvent( String requestId, String producerName, String producerEventName) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.get(mapKey); long currentTime = getTime(); FLog.v( TAG, "time %d: onProducerEvent: {requestId: %s, stage: %s, eventName: %s; elapsedTime: %d ms}", getTime(), requestId, producerName, producerEventName, getElapsedTime(startTime, currentTime)); } } @Override public synchronized void onRequestSuccess( ImageRequest request, String requestId, boolean isPrefetch) { if (FLog.isLoggable(FLog.VERBOSE)) { Long startTime = mRequestStartTimeMap.remove(requestId); long currentTime = getTime(); FLog.v( TAG, "time %d: onRequestSuccess: {requestId: %s, elapsedTime: %d ms}", currentTime, requestId, getElapsedTime(startTime, currentTime)); } } @Override public synchronized void onRequestFailure( ImageRequest request, String requestId, Throwable throwable, boolean isPrefetch) { if (FLog.isLoggable(FLog.WARN)) { Long startTime = mRequestStartTimeMap.remove(requestId); long currentTime = getTime(); FLog.w( TAG, "time %d: onRequestFailure: {requestId: %s, elapsedTime: %d ms, throwable: %s}", currentTime, requestId, getElapsedTime(startTime, currentTime), throwable.toString()); } } @Override public synchronized void onRequestCancellation(String requestId) { if (FLog.isLoggable(FLog.VERBOSE)) { Long startTime = mRequestStartTimeMap.remove(requestId); long currentTime = getTime(); FLog.v( TAG, "time %d: onRequestCancellation: {requestId: %s, elapsedTime: %d ms}", currentTime, requestId, getElapsedTime(startTime, currentTime)); } } @Override public boolean requiresExtraMap(String id) { return FLog.isLoggable(FLog.VERBOSE); } private static long getElapsedTime(@Nullable Long startTime, long endTime) { if (startTime != null) { return endTime - startTime; } return -1; } private static long getTime() { return SystemClock.elapsedRealtime(); } }