Android - Logcat mesajlarının maksimum uzunluğunu ayarla


101

Varsayılan olarak, logcat'in "çok uzun" olduğunu düşündüğü herhangi bir günlük mesajını keseceği görülmektedir. Bu, hem Eclipse içinde hem de komut satırında komut satırında logcat çalıştırırken olur adb -d logcatve bazı önemli hata ayıklama mesajlarını keser.

Hata ayıklama bilgilerini kesmeyi durdurmak için logcat tarafından desteklenen maksimum dize uzunluğunu artırmanın bir yolu var mı? Resmi belgeler olmayabilir ima, ama belki desteklerin logcat bazı ek seçenekler var belirtilmeyen?



Benzer:
Logcat'te


1
@JoshCorreia Bunun iyi bir kopya olduğunu sanmıyorum, çünkü bu toplam arabellek boyutunu ifade ediyor ve bu günlük mesajı başına.
Ryan M

1
@RyanM Ah benim hatam, diğer soruyu yanlış anladım. Teşekkürler, işareti çift olarak kaldırılıyor.
Josh Correia

Yanıtlar:


45

İkili günlükler ( /dev/log/events) için logcat'te sabit boyutlu bir arabellek vardır ve bu sınır 1024 bayttır. İkili olmayan günlükler için ayrıca bir sınır vardır:

#define LOGGER_ENTRY_MAX_LEN        (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))

Dolayısıyla hem ikili hem de ikili olmayan günlükler için gerçek ileti boyutu ~ 4076 bayttır. Çekirdek kaydedici arayüzü bu LOGGER_ENTRY_MAX_PAYLOADsınırı koyar .

Liblog kaynakları (logcat tarafından kullanılır) ayrıca şunu da söyler:

  • İleti, çekirdek günlük sürücüsü tarafından kesilmiş olabilir.

Size logcat ikili dosyasını kullanmayan nxlog aracını tavsiye ederim , ancak çekirdekteki sınırlamalar nedeniyle probleminizi çözeceğinden şüpheliyim. Yine de denemeye değer olabilir. (sorumluluk reddi: Ben yazarım.)


6
Bunu nerede bulabilirim? "Logcat" kodunda mı? Öyleyse, kendi değiştirilmiş logcatimi derlemem gerekir mi?
d4Rk

2
İkili / ikili olmayan günlük nedir?
fobbymaster

2
Eklenen meta veri alanları nedeniyle LOGGER_ENTRY_MAX_PAYLOAD, Android'in daha yeni sürümlerinde 4076'dan 4068'e düşürülmüştür ( buraya bakın ).
mhsmith

88

Tamam, ilginç. Cevabın "onu gerçekten genişletemezsin" olduğunu görünce hayal kırıklığına uğradım. İlk düşüncem onu ​​parçalamaktı, böylece her şeyi görebildim, bu yüzden burada sizlerle bunu nasıl yaptığımı paylaşıyorum (bunun ne süslü ne de verimli olduğunu değil, ama işi bir tutam içinde hallediyor):

if (sb.length() > 4000) {
    Log.v(TAG, "sb.length = " + sb.length());
    int chunkCount = sb.length() / 4000;     // integer division
    for (int i = 0; i <= chunkCount; i++) {
        int max = 4000 * (i + 1);
        if (max >= sb.length()) {
            Log.v(TAG, "chunk " + i + " of " + chunkCount + ":" + sb.substring(4000 * i));
        } else {
            Log.v(TAG, "chunk " + i + " of " + chunkCount + ":" + sb.substring(4000 * i, max));
        }
    }
} else {
    Log.v(TAG, sb.toString());
}

Son dizeyi göstermek için düzenlendi!


Sorun değil! Umarım size yardımcı olmuştur
Travis

Burada bir hata olduğundan oldukça eminim. Son parçayı elde etmek için "i <chunkCount + 1" kullanmak zorunda kaldım
Dan

2
Son dizeyi kaybettiniz: int chunkCount = sb.length() / 4000;Kullanım int chunkCount = sb.length() / 4000; if (chunkCount * 4000 < sb.length()) chunkCount++;
Timur Gilfanov

2
else { Log.v(TAG, sb); }mesaj <= 4000 karakter uzunluğunda olduğunda günlüğü de yazdırmak için ekleyin
Bojan Radivojevic Bombacı

4
Bu yanıt, ASCII olmayan karakterler için yanlıştır. logcat UTF8'i destekler ve sınır 4k bayttır , karakter değil.
miguel

59

Yinelemeli olarak birkaç parçaya bölün.

public static void largeLog(String tag, String content) {
   if (content.length() > 4000) {
       Log.d(tag, content.substring(0, 4000));
       largeLog(tag, content.substring(4000));
   } else {
       Log.d(tag, content);
   }
}

3
Bu açık arayla en temiz çözüm ve üretim kodunda özyinelemeyi ilk kez gerçekten kullandım.
Saldırgan

2
@Aggressor üretimde neden 4000'den fazla uzun mesaj kaydetmeniz gerekiyor?
TWiStErRob

1
Benim kullanım durumum büyük bir json materyali çıkarmaktır. Dosyalar sadece bir acıdır.
Marcel Falliere

1
Çok faydalı teşekkürler. Dizeyi satır sonlarında bölen bir yanıt gönderdim.
sersemlemiş

1
Awesome Simpler Cleaner Havalı ve Güzel. Alkışlar
Muhammed Ashfaq


5

İşte kullandığım kod - 4000 sınırında satırları keserken, aynı zamanda satırın ortalarında değil de yeni satırlarda satırı kesiyor. Günlük dosyasının okunmasını kolaylaştırır.

Kullanım:

Logger.debugEntire("....");

Uygulama:

package ...;

import android.util.Log;

import java.util.Arrays;

public class Logger {

    private static final String LOG_TAG = "MyRockingApp";

    /** @see <a href="http://stackoverflow.com/a/8899735" /> */
    private static final int ENTRY_MAX_LEN = 4000;

    /**
     * @param args If the last argument is an exception than it prints out the stack trace, and there should be no {}
     *             or %s placeholder for it.
     */
    public static void d(String message, Object... args) {
        log(Log.DEBUG, false, message, args);
    }

    /**
     * Display the entire message, showing multiple lines if there are over 4000 characters rather than truncating it.
     */
    public static void debugEntire(String message, Object... args) {
        log(Log.DEBUG, true, message, args);
    }

    public static void i(String message, Object... args) {
        log(Log.INFO, false, message, args);
    }

    public static void w(String message, Object... args) {
        log(Log.WARN, false, message, args);
    }

    public static void e(String message, Object... args) {
        log(Log.ERROR, false, message, args);
    }

    private static void log(int priority, boolean ignoreLimit, String message, Object... args) {
        String print;
        if (args != null && args.length > 0 && args[args.length-1] instanceof Throwable) {
            Object[] truncated = Arrays.copyOf(args, args.length -1);
            Throwable ex = (Throwable) args[args.length-1];
            print = formatMessage(message, truncated) + '\n' + android.util.Log.getStackTraceString(ex);
        } else {
            print = formatMessage(message, args);
        }
        if (ignoreLimit) {
            while (!print.isEmpty()) {
                int lastNewLine = print.lastIndexOf('\n', ENTRY_MAX_LEN);
                int nextEnd = lastNewLine != -1 ? lastNewLine : Math.min(ENTRY_MAX_LEN, print.length());
                String next = print.substring(0, nextEnd /*exclusive*/);
                android.util.Log.println(priority, LOG_TAG, next);
                if (lastNewLine != -1) {
                    // Don't print out the \n twice.
                    print = print.substring(nextEnd+1);
                } else {
                    print = print.substring(nextEnd);
                }
            }
        } else {
            android.util.Log.println(priority, LOG_TAG, print);
        }
    }

    private static String formatMessage(String message, Object... args) {
        String formatted;
        try {
            /*
             * {} is used by SLF4J so keep it compatible with that as it's easy to forget to use %s when you are
             * switching back and forth between server and client code.
             */
            formatted = String.format(message.replaceAll("\\{\\}", "%s"), args);
        } catch (Exception ex) {
            formatted = message + Arrays.toString(args);
        }
        return formatted;
    }
}

4

Aşağıdaki kod, Mark Buikema tarafından yazılanların bir düzeltmesidir. Dizeyi yeni satırlarda keser. Uzun JSON dizelerini günlüğe kaydetmek için kullanışlıdır.

  public static void dLong(String theMsg)
  {
    final int MAX_INDEX = 4000;
    final int MIN_INDEX = 3000;

    // String to be logged is longer than the max...
    if (theMsg.length() > MAX_INDEX)
    {
      String theSubstring = theMsg.substring(0, MAX_INDEX);
      int    theIndex = MAX_INDEX;

      // Try to find a substring break at a line end.
      theIndex = theSubstring.lastIndexOf('\n');
      if (theIndex >= MIN_INDEX)
      {
        theSubstring = theSubstring.substring(0, theIndex);
      }
      else
      {
        theIndex = MAX_INDEX;
      }

      // Log the substring.
      Log.d(APP_LOG_TAG, theSubstring);

      // Recursively log the remainder.
      dLong(theMsg.substring(theIndex));
    }

    // String to be logged is shorter than the max...
    else
    {
      Log.d(APP_LOG_TAG, theMsg);
    }
  }

3
int i = 3000;
while (sb.length() > i) {
    Log.e(TAG, "Substring: "+ sb.substring(0, i));
    sb = sb.substring(i);
}
Log.e(TAG, "Substring: "+ sb);

2

bize bu çağrı mantığını

    /*
     * StringBuffer sb - long text which want to show in multiple lines 
     * int lenth - lenth of line need
     */

public static void showInPage(StringBuffer sb, int lenth) {
    System.out.println("sb.length = " + sb.length());
    if (sb.length() > lenth) {

        int chunkCount = sb.length() / lenth; // integer division
        if ((chunkCount % lenth) > 1)
            chunkCount++;
        for (int i = 0; i < chunkCount; i++) {
            int max = lenth * (i + 1);
            if (max >= sb.length()) {
                System.out.println("");
                System.out.println("chunk " + i + " of " + chunkCount + ":"
                        + sb.substring(lenth * i));
            } else {
                System.out.println("");
                System.out.println("chunk " + i + " of " + chunkCount + ":"
                        + sb.substring(lenth * i, max));
            }
        }
    }

}

1

Travis'in çözümüyle ilgili kendi görüşümü sunuyorum,

void d(String msg) {
  println(Log.DEBUG, msg);
}

private void println(int priority, String msg) {
    int l = msg.length();
    int c = Log.println(priority, TAG, msg);
    if (c < l) {
        return c + println(priority, TAG, msg.substring(c+1));
    } else {
        return c;
    }
}

Log.println()"4000" kodlamasını engellemek için yazılan bayt sayısını döndüren gerçeğinden yararlanın . daha sonra, hiçbir şey kalmayana kadar kaydedilemeyen mesaj bölümünde kendinizi yinelemeli olarak arayın.


Ne yazık ki, println yazılan bayt sayısını ve! = Bayt karakterlerini döndürür.
gnuf

1
iyi çalışıyor. Sanırım, çünkü sadece ascii metni kaydediyorum.
Jeffrey Blattman

1

Günlüğünüz çok uzunsa (örneğin, hata ayıklama nedenleriyle veritabanınızın tüm dökümünü günlüğe kaydetmek vb.), Logcat aşırı günlüğe kaydetmeyi engelleyebilir. Bunu aşmak için her x milisaniye için bir zaman aşımı ekleyebilirsiniz.

/**
 * Used for very long messages, splits it into equal chunks and logs each individual to
 * work around the logcat max message length. Will log with {@link Log#d(String, String)}.
 *
 * @param tag     used in for logcat
 * @param message long message to log
 */
public static void longLogDebug(final String tag, @NonNull String message) {
    int i = 0;

    final int maxLogLength = 1000;
    while (message.length() > maxLogLength) {
        Log.d(tag, message.substring(0, maxLogLength));
        message = message.substring(maxLogLength);
        i++;

        if (i % 100 == 0) {
            StrictMode.noteSlowCall("wait to flush logcat");
            SystemClock.sleep(32);
        }
    }
    Log.d(tag, message);
}

Dikkat edin, bunu yalnızca hata ayıklama amacıyla kullanın, çünkü ana iş parçacığının bloklarını durdurabilir.


1

@Mhsmith'in bahsettiği gibi, LOGGER_ENTRY_MAX_PAYLOADson Android sürümlerinde 4068'dir . Ancak, diğer yanıtlarda sunulan kod parçacıklarında maksimum mesaj uzunluğu olarak 4068 kullanırsanız, mesajlar kesilecektir. Bunun nedeni, Android'in mesajınızın başına ve sonuna daha fazla karakter eklemesi ve bu da önemli olmasıdır. Diğer yanıtlar 4000 sınırını geçici çözüm olarak kullanır. Bununla birlikte, bu kodla tüm sınırı gerçekten kullanmak mümkündür (kod, sınıf adını ve günlüğü çağıran satır numarasını göstermek için yığın izlemeden bir etiket oluşturur, bunu değiştirmekten çekinmeyin):

private static final int MAX_MESSAGE_LENGTH = 4068;

private enum LogType {
    debug,
    info,
    warning,
    error
}

private static void logMessage(LogType logType, @Nullable String message, @Nullable String tag) {
    logMessage(logType, message, tag, Thread.currentThread().getStackTrace()[4]);
}

private static void logMessage(LogType logType, @Nullable String message, @Nullable String customTag, StackTraceElement stackTraceElement) {
    // don't use expensive String.format
    String tag = "DASHBOARDS(" + stackTraceElement.getFileName() + "." + (!TextUtils.isEmpty(customTag) ? customTag : stackTraceElement.getMethodName()) + ":" + stackTraceElement.getLineNumber() + ")";
    int maxMessageLength = MAX_MESSAGE_LENGTH - (tag.length()) - 4; // minus four because android adds a letter showing the log type before the tag, e. g. "D/" for debug, and a colon and space are added behind it, i. e. ": "
    if (message == null || message.length() <= maxMessageLength) {
        logMessageInternal(logType, message, tag);
    } else {
        maxMessageLength -= 8; // we will add counter to the beginning of the message, e. g. "(12/15) "
        int totalChunks = (int) Math.ceil((float) message.length() / maxMessageLength);
        for (int i = 1; i <= totalChunks; i++) {
            int start = (i - 1) * maxMessageLength;
            logMessageInternal(logType, "(" + i + "/" + totalChunks + ") " + message.substring(start, Math.min(start + maxMessageLength, message.length())), tag);
        }
    }
}

private static void logMessageInternal(LogType logType, String message, String tag) {
    if (message == null) {
        message = "message is null";
    }
    switch (logType) {
        case debug:
            Log.d(tag, message);
            break;
        case info:
            Log.i(tag, message);
            break;
        case warning:
            Log.w(tag, message);
            break;
        case error:
            Log.e(tag, message);
    }
}

public static void d(String debug, String tag) {
    logMessage(LogType.debug, debug, tag);
}

0

Logcat'in uzunluğunu artırmak için herhangi bir seçenek bilmiyorum, ancak ana günlük, olay günlüğü vb. Gibi farklı günlükleri bulabiliriz. Ana günlük genellikle uzunluğu 4Mb'ye kadar olan her şeyi içerir. Böylece kaybettiklerinizi elde edebilirsiniz. günlük terminalinde. Yol: \ data \ logger.


0

Sağlanan diğer çözümler yardımcı olsa da, onlardan memnun kalmadım çünkü günlüğün @ b0ti tarafından bahsedilen LOGGER_ENTRY_MAX_LEN'in iki katından daha uzun olduğu durumları kapsamadılar. Ayrıca LOGGER_ENTRY_MAX_LEN dinamik olarak getirilmediğinden aşağıdaki çözümüm bile mükemmel değil. Birisi bunu yapmanın bir yolunu biliyorsa, bunu yorumlarda duymak isterim! Her neyse, şu anda kodumda kullandığım çözüm bu:

final int loggerEntryMaxLength = 4000;
int logLength = loggerEntryMaxLength - 2 - TAG.length();
int i = 0;
while (output.length() / logLength > i) {
    int startIndex = i++ * logLength;
    int endIndex = i * logLength;
    Log.d(TAG, output.substring(startIndex, endIndex));
}
int startIndex = i * logLength;
Log.d(
        TAG,
        output.substring(
                startIndex,
                startIndex + (output.length() % logLength)
        )
);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.