112

I am trying to display long message on logcat. If the length of message is more than 1000 characters, it gets broken.

What is the mechanism to show all characters of long message in logcat?

Oak Bytes
  • 4,649
  • 4
  • 36
  • 53
Vasu
  • 2,673
  • 5
  • 20
  • 17

12 Answers12

170

If logcat is capping the length at 1000 then you can split the string you want to log with String.subString() and log it in pieces. For example:

int maxLogSize = 1000;
for(int i = 0; i <= veryLongString.length() / maxLogSize; i++) {
    int start = i * maxLogSize;
    int end = (i+1) * maxLogSize;
    end = end > veryLongString.length() ? veryLongString.length() : end;
    Log.v(TAG, veryLongString.substring(start, end));
}
mamba4ever
  • 2,662
  • 4
  • 28
  • 46
spatulamania
  • 6,613
  • 2
  • 30
  • 26
  • 1
    Log cat printing only half of the response.. how could i get the length of the whole response . you said that veryLongString.length() but here its printed only half the response when i print the json result in log cat – Vasu Sep 30 '11 at 05:26
  • But in iphone console I am getting the whole response string – Vasu Sep 30 '11 at 05:26
  • you can check the length of the response by writing length() to the log. If this value isn't what you expected, the problem might not be with logging. – spatulamania Sep 30 '11 at 05:29
  • Be extra careful with this approach! In Android M you might get `OutOfMemoryError` followed by application crash. – Toochka Nov 02 '15 at 12:54
  • 4
    Can't believe Android make it so hard! – Alston Dec 26 '15 at 09:34
  • 1
    I think this code will log an extra, empty log entry at the end, if `veryLongString.length()` is a multiple of `maxLogSize`. Maybe change the `<=` to `<`. – LarsH Feb 06 '16 at 16:29
  • @spatulamania good work it's work for me keep it programing ;) – Bipin Bharti Apr 21 '17 at 05:35
  • Please see @LarsH answer below for a single liner loop – Bugs Happen Mar 01 '18 at 07:36
  • How do display a very long json in logcat in prettified form – Shikhar Feb 16 '19 at 06:09
  • I've found that calculating `end` like so made it cleaner and easier to read: `int end = Math.min( veryLongString.length(), start + maxLogSize );` – Thomas Elliot Mar 23 '19 at 00:07
34

As a follow on to spatulamania answer I wrote a wrapper class which handles this for you. You just need to change the import and it will log everything

public class Log {

    public static void d(String TAG, String message) {
        int maxLogSize = 2000;
        for(int i = 0; i <= message.length() / maxLogSize; i++) {
            int start = i * maxLogSize;
            int end = (i+1) * maxLogSize;
            end = end > message.length() ? message.length() : end;
            android.util.Log.d(TAG, message.substring(start, end));
        }
    }

}
jiduvah
  • 5,108
  • 6
  • 39
  • 55
26

This builds on spatulamania's answer, is a little more succinct, and won't add an empty log message at the end:

final int chunkSize = 2048;
for (int i = 0; i < s.length(); i += chunkSize) {
    Log.d(TAG, s.substring(i, Math.min(s.length(), i + chunkSize)));
}
LarsH
  • 27,481
  • 8
  • 94
  • 152
13

Try this piece of code to show long message in logcat.

public void logLargeString(String str) {
    if(str.length() > 3000) {
        Log.i(TAG, str.substring(0, 3000));
        logLargeString(str.substring(3000));
    } else {
        Log.i(TAG, str); // continuation
    }
}
spaceMonkey
  • 4,475
  • 4
  • 26
  • 34
Mani
  • 3,394
  • 3
  • 30
  • 36
  • 9
    when a simple loop will be sufficient, why use recursion. – pellucide May 13 '15 at 18:36
  • 3
    I am a fan of recursion as I find the readibilty and reuse of code great. However this tail end recursion can build up stack frames quickly if your compiler doesn't optimise them (which I don't believe the Android studio one does). This means that if you have a substantially long message that causes a pluribus of recursive calls you can easy create a StackOverflowError. – Luke Mar 04 '16 at 02:12
  • 1
    @pellucide show how to do it with a "simple loop" – Fernando Torres Feb 24 '21 at 08:49
11

This is how OkHttp with HttpLoggingInterceptor does it:

public void log(String message) {
  // Split by line, then ensure each line can fit into Log's maximum length.
  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 + MAX_LOG_LENGTH);
      Log.d("OkHttp", message.substring(i, end));
      i = end;
    } while (i < newline);
  }
}

MAX_LOG_LENGTH is 4000.

Here it use Log.d (debug) and hardcoded "OkHttp" tag.

It split the log at newlines or when it reach the max length.

This class below is an helper class you can use (if you have lambda support throw Jack & Jill or retrolambda) to do the same thing OkHttp does on any log:

/**
 * Help printing logs splitting text on new line and creating multiple logs for too long texts
 */

public class LogHelper {

    private static final int MAX_LOG_LENGTH = 4000;

    public static void v(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.v(tag, line));
    }

    public static void d(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.d(tag, line));
    }

    public static void i(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.i(tag, line));
    }

    public static void w(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.w(tag, line));
    }

    public static void e(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.e(tag, line));
    }

    public static void v(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.v(tag, line));
    }

    public static void d(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.d(tag, line));
    }

    public static void i(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.i(tag, line));
    }

    public static void w(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.w(tag, line));
    }

    public static void e(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.e(tag, line));
    }

    private static void log(@Nullable String message, @NonNull LogCB callback) {
        if (message == null) {
            callback.log("null");
            return;
        }
        // Split by line, then ensure each line can fit into Log's maximum length.
        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 + MAX_LOG_LENGTH);
                callback.log(message.substring(i, end));
                i = end;
            } while (i < newline);
        }
    }

    private static void log(@Nullable String message, @Nullable Throwable throwable, @NonNull LogCB callback) {
        if (throwable == null) {
            log(message, callback);
            return;
        }
        if (message != null) {
            log(message + "\n" + Log.getStackTraceString(throwable), callback);
        } else {
            log(Log.getStackTraceString(throwable), callback);
        }
    }

    private interface LogCB {
        void log(@NonNull String message);
    }
}
Daniele Segato
  • 12,314
  • 6
  • 62
  • 88
4

With Kotlin we can make use of the stdlib chunked function:

fun logUnlimited(tag: String, string: String) {
    val maxLogSize = 1000
    string.chunked(maxLogSize).forEach { Log.v(tag, it) }
}
Luke Needham
  • 3,373
  • 1
  • 24
  • 41
3

In order not to minimize splitting lines across log messages, I take the large string and log each line separately.

void logMultilineString(String data) {
    for (String line : data.split("\n")) {
        logLargeString(line);
    }
}

void logLargeString(String data) {
    final int CHUNK_SIZE = 4076;  // Typical max logcat payload.
    int offset = 0;
    while (offset + CHUNK_SIZE <= data.length()) {
        Log.d(TAG, data.substring(offset, offset += CHUNK_SIZE));
    }
    if (offset < data.length()) {
        Log.d(TAG, data.substring(offset));
    }
}
vonWippersnap
  • 483
  • 3
  • 9
2

I consider Timber a good option for this issue. Timber automatically split and print chunks of message in logcat.

https://github.com/JakeWharton/timber

You can see log method implementation in timber.log.Timber.DebugTree static class.

1

Here is a Kotlin version for the @spatulamania answer (especially for lazy/smart peooples):

val maxLogSize = 1000
val stringLength = yourString.length
for (i in 0..stringLength / maxLogSize) {
    val start = i * maxLogSize
    var end = (i + 1) * maxLogSize
    end = if (end > yourString.length) yourString.length else end
    Log.v("YOURTAG", yourString.substring(start, end))
}
Filipe Brito
  • 5,329
  • 5
  • 32
  • 42
0

if print json string, can use code below

    @JvmStatic
    fun j(level: Int, tag: String? = null, msg: String) {
        if (debug) {
            if (TextUtils.isEmpty(msg)) {
                p(level, tag, msg)
            } else {
                val message: String
                message = try {
                    when {
                        msg.startsWith("{") -> {
                            val jsonObject = JSONObject(msg)
                            jsonObject.toString(4)
                        }
                        msg.startsWith("[") -> {
                            val jsonArray = JSONArray(msg)
                            jsonArray.toString(4)
                        }
                        else -> msg
                    }
                } catch (e: JSONException) {
                    e.printStackTrace()
                    msg
                }
                p(level, tag, "╔═══════════════════════════════════════════════════════════════════════════════════════", false)
                val lines = message.split(LINE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                for (line in lines) {
                    p(level, tag, "║ $line", false)
                }
                p(level, tag, "╚═══════════════════════════════════════════════════════════════════════════════════════", false)
            }
        }
    }

full code

CXLogUtil.j("json-tag","{}")

preview result

Michael Mao
  • 433
  • 5
  • 9
0
        public static void largeLog(String tag, String content) {
            final int SEG_LENGTH = 4000;
            do {
                if (content.length() <= SEG_LENGTH) {
                    Log.d(tag, content);
                    break;
                }
                Log.d(tag, content.substring(0, SEG_LENGTH));
                content = content.substring(SEG_LENGTH);
            } while (!content.isEmpty());
        }
tteng little
  • 161
  • 1
  • 1
  • 6
-3

For an easy solution, use Use soft wrap option in below attach point no 4 options might help you.

Mohit Suthar
  • 8,725
  • 10
  • 37
  • 67