Created
April 26, 2016 16:00
-
-
Save SmartDengg/1938c7f25e4baa1f7c846a3c40739a7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.smartdengg.model.repository.interceptor; | |
| import android.support.annotation.NonNull; | |
| import android.util.Log; | |
| import com.smartdengg.common.Constants; | |
| import java.io.IOException; | |
| import java.nio.charset.Charset; | |
| import java.util.concurrent.TimeUnit; | |
| import okhttp3.Connection; | |
| import okhttp3.Headers; | |
| import okhttp3.Interceptor; | |
| import okhttp3.MediaType; | |
| import okhttp3.Protocol; | |
| import okhttp3.Request; | |
| import okhttp3.RequestBody; | |
| import okhttp3.Response; | |
| import okhttp3.ResponseBody; | |
| import okhttp3.internal.http.HttpEngine; | |
| import okio.Buffer; | |
| import okio.BufferedSource; | |
| /** | |
| * Created by SmartDengg on 2016/3/31. | |
| */ | |
| public class SmartHttpLoggingInterceptor implements Interceptor { | |
| private static final Charset UTF8 = Charset.forName("UTF-8"); | |
| private final Logger logger; | |
| private volatile Level level = Level.NONE; | |
| private static final char TOP_LEFT_CORNER = '╔'; | |
| private static final char BOTTOM_LEFT_CORNER = '╚'; | |
| private static final char MIDDLE_CORNER = '╟'; | |
| public static final char HORIZONTAL_DOUBLE_LINE = '║'; | |
| private static final String DOUBLE_DIVIDER = "════════════════════════════════════════════"; | |
| private static final String SINGLE_DIVIDER = "────────────────────────────────────────────"; | |
| public static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; | |
| public static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; | |
| public static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER; | |
| public enum Level { | |
| /** No logs. */ | |
| NONE, | |
| /** | |
| * Logs request and response lines. | |
| * <p>Example: | |
| * <pre>{@code | |
| * --> POST /greeting HTTP/1.1 (3-byte body) | |
| * <-- HTTP/1.1 200 OK (22ms, 6-byte body) | |
| * }</pre> | |
| */ | |
| BASIC, | |
| /** | |
| * Logs request and response lines and their respective headers. | |
| * <p>Example: | |
| * <pre>{@code | |
| * --> POST /greeting HTTP/1.1 | |
| * Host: example.com | |
| * Content-Type: plain/text | |
| * Content-Length: 3 | |
| * --> END POST | |
| * <-- HTTP/1.1 200 OK (22ms) | |
| * Content-Type: plain/text | |
| * Content-Length: 6 | |
| * <-- END HTTP | |
| * }</pre> | |
| */ | |
| HEADERS, | |
| /** | |
| * Logs request and response lines and their respective headers and bodies (if present). | |
| * <p>Example: | |
| * <pre>{@code | |
| * --> POST /greeting HTTP/1.1 | |
| * Host: example.com | |
| * Content-Type: plain/text | |
| * Content-Length: 3 | |
| * Hi? | |
| * --> END GET | |
| * <-- HTTP/1.1 200 OK (22ms) | |
| * Content-Type: plain/text | |
| * Content-Length: 6 | |
| * Hello! | |
| * <-- END HTTP | |
| * }</pre> | |
| */ | |
| BODY | |
| } | |
| public interface Logger { | |
| void log(String message); | |
| void logRequestBody(String message); | |
| void logTopBorder(); | |
| void logMiddleBorder(); | |
| void logBottomBorder(); | |
| } | |
| /** A {@link Logger} defaults output appropriate for the current platform. */ | |
| private static Logger DEFAULT = new Logger() { | |
| @Override | |
| public void log(String message) { | |
| for (int i = 0, length = message.length(); i < length; i++) { | |
| int newline = message.indexOf('\n', i); | |
| newline = newline != -1 ? newline : length; | |
| do { | |
| int end = Math.min(newline, i + Constants.MAX_LOG_LENGTH); | |
| Log.d(Constants.BASE_TAG + "-" + Constants.OKHTTP_TAG, SmartHttpLoggingInterceptor.HORIZONTAL_DOUBLE_LINE + message.substring(i, end)); | |
| i = end; | |
| } while (i < newline); | |
| } | |
| } | |
| @Override | |
| public void logRequestBody(String message) { | |
| this.log(" ⇢⇢⇢⇢ " + message); | |
| } | |
| @Override | |
| public void logTopBorder() { | |
| Log.d(Constants.BASE_TAG + "-" + Constants.OKHTTP_TAG, SmartHttpLoggingInterceptor.TOP_BORDER); | |
| } | |
| @Override | |
| public void logMiddleBorder() { | |
| Log.d(Constants.BASE_TAG + "-" + Constants.OKHTTP_TAG, SmartHttpLoggingInterceptor.MIDDLE_BORDER); | |
| } | |
| @Override | |
| public void logBottomBorder() { | |
| Log.d(Constants.BASE_TAG + "-" + Constants.OKHTTP_TAG, SmartHttpLoggingInterceptor.BOTTOM_BORDER); | |
| } | |
| }; | |
| public static SmartHttpLoggingInterceptor createLoggingInterceptor() { | |
| return new SmartHttpLoggingInterceptor(); | |
| } | |
| public SmartHttpLoggingInterceptor() { | |
| this(DEFAULT); | |
| } | |
| public SmartHttpLoggingInterceptor(Logger logger) { | |
| this.logger = logger; | |
| } | |
| /** Change the level at which this interceptor logs. */ | |
| public SmartHttpLoggingInterceptor setLevel(@NonNull Level level) { | |
| if (level == null) { | |
| throw new NullPointerException("level == null. Use Level.NONE instead."); | |
| } | |
| this.level = level; | |
| return this; | |
| } | |
| public Level getLevel() { | |
| return level; | |
| } | |
| @Override | |
| public Response intercept(Chain chain) throws IOException { | |
| Level level = this.level; | |
| Request request = chain.request(); | |
| if (level == Level.NONE) { | |
| return chain.proceed(request); | |
| } | |
| boolean logBody = level == Level.BODY; | |
| boolean logHeaders = logBody || level == Level.HEADERS; | |
| RequestBody requestBody = request.body(); | |
| boolean hasRequestBody = requestBody != null; | |
| Connection connection = chain.connection(); | |
| Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; | |
| String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol(protocol); | |
| if (!logHeaders && hasRequestBody) { | |
| requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; | |
| } | |
| /**Outputs Top_Border*/ | |
| logger.logTopBorder(); | |
| logger.log(requestStartMessage); | |
| if (logHeaders) { | |
| if (hasRequestBody) { | |
| // Request body headers are only present when installed as a network interceptor. | |
| // Force | |
| // them to be included (when available) so there values are known. | |
| if (requestBody.contentType() != null) { | |
| logger.log("Content-Type: " + requestBody.contentType()); | |
| } | |
| if (requestBody.contentLength() != -1) { | |
| logger.log("Content-Length: " + requestBody.contentLength()); | |
| } | |
| } | |
| Headers headers = request.headers(); | |
| for (int i = 0, count = headers.size(); i < count; i++) { | |
| String name = headers.name(i); | |
| // Skip headers from the request body as they are explicitly logged above. | |
| if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { | |
| logger.log(name + ": " + headers.value(i)); | |
| } | |
| } | |
| if (!logBody || !hasRequestBody) { | |
| logger.log("--> END " + request.method()); | |
| } else if (bodyEncoded(request.headers())) { | |
| logger.log("--> END " + request.method() + " (encoded body omitted)"); | |
| } else { | |
| Buffer buffer = new Buffer(); | |
| requestBody.writeTo(buffer); | |
| Charset charset = UTF8; | |
| MediaType contentType = requestBody.contentType(); | |
| if (contentType != null) { | |
| charset = contentType.charset(UTF8); | |
| } | |
| if (requestBody.contentLength() > 0) { | |
| logger.log(""); | |
| logger.logRequestBody(buffer.readString(charset)); | |
| } | |
| logger.log("--> END " + request.method() + " (" + requestBody.contentLength() + "-byte body)"); | |
| } | |
| } | |
| /**Outputs Middle_Border*/ | |
| logger.logMiddleBorder(); | |
| long startNs = System.nanoTime(); | |
| Response response = chain.proceed(request); | |
| long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); | |
| ResponseBody responseBody = response.body(); | |
| long contentLength = responseBody.contentLength(); | |
| String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; | |
| logger.log("<-- " + response.code() + ' ' + response.message() + ' ' + response.request().url() + " (" + tookMs + "ms" + | |
| (!logHeaders ? ", " + bodySize + " body" : "") + ')'); | |
| if (logHeaders) { | |
| Headers headers = response.headers(); | |
| for (int i = 0, count = headers.size(); i < count; i++) { | |
| logger.log(headers.name(i) + ": " + headers.value(i)); | |
| } | |
| /**Outputs Middle_Border*/ | |
| logger.logMiddleBorder(); | |
| if (!logBody || !HttpEngine.hasBody(response)) { | |
| logger.log("<-- END HTTP"); | |
| } else if (bodyEncoded(response.headers())) { | |
| logger.log("<-- END HTTP (encoded body omitted)"); | |
| } else { | |
| BufferedSource source = responseBody.source(); | |
| source.request(Long.MAX_VALUE); // Buffer the entire body. | |
| Buffer buffer = source.buffer(); | |
| /* Charset charset = UTF8; | |
| MediaType contentType = responseBody.contentType(); | |
| if (contentType != null) { | |
| charset = contentType.charset(UTF8); | |
| } | |
| if (contentLength != 0) { | |
| logger.log(""); | |
| logger.log(buffer.clone().readString(charset)); | |
| }*/ | |
| logger.log("<-- END HTTP (" + buffer.size() + "-byte body)"); | |
| } | |
| } | |
| /**Outputs Middle_Border*/ | |
| logger.logBottomBorder(); | |
| return response; | |
| } | |
| private boolean bodyEncoded(Headers headers) { | |
| String contentEncoding = headers.get("Content-Encoding"); | |
| return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); | |
| } | |
| private static String protocol(Protocol protocol) { | |
| return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1"; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment