Logcat'i uygulama içinde programlı olarak okuyun


116

Uygulamamdaki logcat günlüklerini okumak ve bunlara tepki vermek istiyorum.

Aşağıdaki kodu buldum:

try {
  Process process = Runtime.getRuntime().exec("logcat -d");
  BufferedReader bufferedReader = new BufferedReader(
  new InputStreamReader(process.getInputStream()));

  StringBuilder log=new StringBuilder();
  String line = "";
  while ((line = bufferedReader.readLine()) != null) {
    log.append(line);
  }
  TextView tv = (TextView)findViewById(R.id.textView1);
  tv.setText(log.toString());
  } 
catch (IOException e) {}

Bu kod gerçekten de uygulama başlatılana kadar yapılan logcat günlüklerini döndürür -

Ancak yeni logcat günlüklerini bile sürekli olarak dinlemek mümkün mü?


1
-D seçeneği günlüğü döker ve çıkar. Sadece -d seçeneğini kaldırın ve logcat çıkmayacaktır.
Frohnzie

1
Nasıl temizleyebilirim? - Başvurumla ilgili belirli bir satır bulmam gerekiyor
David,

1
Kök gerekmez.
Luis

2
Kök gerekli değilse, yalnızca geliştirme derlemesi kendi günlüğüne erişebilir mi? Ve bu kod tam olarak nerede çalıştırılır? apk uygulamasında?
Ayyappa

2
Bir test denedim. Sadece kendi sürecimin olaylarını okuyabildim. Diğer süreç olaylarını okumak için root'a ihtiyacınız olduğunu düşünüyorum.
Yetti99

Yanıtlar:


55

Yukarıdaki kodunuzdaki "-d" bayrağını kaldırarak günlükleri okumaya devam edebilirsiniz.

"-D" bayrağı logcat'e günlük içeriğini göstermesi ve çıkması talimatını verir. Bayrağı kaldırırsanız, logcat sona ermez ve ona eklenen yeni bir satır göndermeye devam eder.

Doğru tasarlanmazsa bunun uygulamanızı engelleyebileceğini unutmayın.

iyi şanslar.


"-D" yi kaldırırsam uygulama sıkışmış ve zorla kapat iletişim kutusunu alıyorum.
David

21
Yukarıda da söylediğim gibi, dikkatli bir uygulama tasarımı gerektirecekti. Yukarıdaki kodu ayrı bir iş parçacığında çalıştırmanız gerekir (kullanıcı arayüzünü engellemekten kaçınmak için) ve kullanıcı arayüzündeki metin görünümünü günlük bilgileriyle güncellemek istediğinizde, bilgileri kullanıcı arayüzüne geri göndermek için bir İşleyici kullanmanız gerekir.
Luis

2
Merhaba Luis, lütfen ayrılmış bir iş parçacığının örnek kodunu gönderebilir misiniz?
img.simone

Cevaba bakın stackoverflow.com/a/59511458/1185087 , UI iş parçacığını engellemeyen eş diziler kullanıyor.
user1185087

8

Yinelenen satırlardan kaçınmak için logcat'i bir dosyaya yazdıktan sonra temizlemek için kullandığım bu yöntemle logcat'inizi temizleyebilirsiniz:

public void clearLog(){
     try {
         Process process = new ProcessBuilder()
         .command("logcat", "-c")
         .redirectErrorStream(true)
         .start();
    } catch (IOException e) {
    }
}

Günlüğü temizlemenin biraz zaman alabileceğini keşfettim. Dolayısıyla, günlüğü temizler ve ardından günlüğü hemen okursanız, bazı eski girişler henüz silinmemiş olabilir. Ayrıca, bazı yeni eklenen günlük girişleri, temizleme tamamlanmadan eklendikleri için silinebilir. Process.waitfor () 'u çağırsanız bile bir fark yaratmaz.
Tom Rutchik

6

Eşgörünümler ve resmi yaşam döngüsü yaşanılan veriler-ktx ve yaşam döngüsü görünüm modeli-ktx kitaplıkları ile bu basit:

class LogCatViewModel : ViewModel() {
    fun logCatOutput() = liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
        Runtime.getRuntime().exec("logcat -c")
        Runtime.getRuntime().exec("logcat")
                .inputStream
                .bufferedReader()
                .useLines { lines -> lines.forEach { line -> emit(line) }
        }
    }
}

kullanım

val logCatViewModel by viewModels<LogCatViewModel>()

logCatViewModel.logCatOutput().observe(this, Observer{ logMessage ->
    logMessageTextView.append("$logMessage\n")
})

Harika bir öneri. Bunun WebViewyerine bunun çalışmasını sağlamanın bir yolu var mı merak ediyorum TextView.
Fatih

4

İşte tüm mevcut veya tüm yeni (son istekten itibaren) günlük öğelerini yakalamak için kullanılabilecek hızlı bir araya getirme / bırakma.

Bunu değiştirmeli / genişletmelisiniz, çünkü bir LogCapture yerine sürekli bir akış döndürmek isteyebilirsiniz.

Android LogCat "Kılavuzu": https://developer.android.com/studio/command-line/logcat.html

import android.util.Log;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Stack;

/**
* Created by triston on 6/30/17.
*/

public class Logger {

  // http://www.java2s.com/Tutorial/Java/0040__Data-Type/SimpleDateFormat.htm
  private static final String ANDROID_LOG_TIME_FORMAT = "MM-dd kk:mm:ss.SSS";
  private static SimpleDateFormat logCatDate = new SimpleDateFormat(ANDROID_LOG_TIME_FORMAT);

  public static String lineEnding = "\n";
  private final String logKey;

  private static List<String> logKeys = new ArrayList<String>();

  Logger(String tag) {
    logKey = tag;
    if (! logKeys.contains(tag)) logKeys.add(logKey);
  }

  public static class LogCapture {
    private String lastLogTime = null;
    public final String buffer;
    public final List<String> log, keys;
    LogCapture(String oLogBuffer, List<String>oLogKeys) {
      this.buffer = oLogBuffer;
      this.keys = oLogKeys;
      this.log = new ArrayList<>();
    }
    private void close() {
      if (isEmpty()) return;
      String[] out = log.get(log.size() - 1).split(" ");
      lastLogTime = (out[0]+" "+out[1]);
    }
    private boolean isEmpty() {
      return log.size() == 0;
    }
    public LogCapture getNextCapture() {
      LogCapture capture = getLogCat(buffer, lastLogTime, keys);
      if (capture == null || capture.isEmpty()) return null;
      return capture;
    }
    public String toString() {
      StringBuilder output = new StringBuilder();
      for (String data : log) {
        output.append(data+lineEnding);
      }
      return output.toString();
    }
  }

  /**
   * Get a list of the known log keys
   * @return copy only
   */
  public static List<String> getLogKeys() {
    return logKeys.subList(0, logKeys.size() - 1);
  }

  /**
   * Platform: Android
   * Get the logcat output in time format from a buffer for this set of static logKeys.
   * @param oLogBuffer logcat buffer ring
   * @return A log capture which can be used to make further captures.
   */
  public static LogCapture getLogCat(String oLogBuffer) { return getLogCat(oLogBuffer, null, getLogKeys()); }

  /**
   * Platform: Android
   * Get the logcat output in time format from a buffer for a set of log-keys; since a specified time.
   * @param oLogBuffer logcat buffer ring
   * @param oLogTime time at which to start capturing log data, or null for all data
   * @param oLogKeys logcat tags to capture
   * @return A log capture; which can be used to make further captures.
   */
  public static LogCapture getLogCat(String oLogBuffer, String oLogTime, List<String> oLogKeys) {
    try {

      List<String>sCommand = new ArrayList<String>();
      sCommand.add("logcat");
      sCommand.add("-bmain");
      sCommand.add("-vtime");
      sCommand.add("-s");
      sCommand.add("-d");

      sCommand.add("-T"+oLogTime);

      for (String item : oLogKeys) sCommand.add(item+":V"); // log level: ALL
      sCommand.add("*:S"); // ignore logs which are not selected

      Process process = new ProcessBuilder().command(sCommand).start();

      BufferedReader bufferedReader = new BufferedReader(
        new InputStreamReader(process.getInputStream()));

      LogCapture mLogCapture = new LogCapture(oLogBuffer, oLogKeys);
      String line = "";

      long lLogTime = logCatDate.parse(oLogTime).getTime();
      if (lLogTime > 0) {
        // Synchronize with "NO YEAR CLOCK" @ unix epoch-year: 1970
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(oLogTime));
        calendar.set(Calendar.YEAR, 1970);
        Date calDate = calendar.getTime();
        lLogTime = calDate.getTime();
      }

      while ((line = bufferedReader.readLine()) != null) {
        long when = logCatDate.parse(line).getTime();
        if (when > lLogTime) {
          mLogCapture.log.add(line);
          break; // stop checking for date matching
        }
      }

      // continue collecting
      while ((line = bufferedReader.readLine()) != null) mLogCapture.log.add(line);

      mLogCapture.close();
      return mLogCapture;
    } catch (Exception e) {
      // since this is a log reader, there is nowhere to go and nothing useful to do
      return null;
    }
  }

  /**
   * "Error"
   * @param e
   */
  public void failure(Exception e) {
    Log.e(logKey, Log.getStackTraceString(e));
  }

  /**
   * "Error"
   * @param message
   * @param e
   */
  public void failure(String message, Exception e) {
    Log.e(logKey, message, e);
  }

  public void warning(String message) {
    Log.w(logKey, message);
  }

  public void warning(String message, Exception e) {
    Log.w(logKey, message, e);
  }

  /**
   * "Information"
   * @param message
   */
  public void message(String message) {
    Log.i(logKey, message);
  }

  /**
   * "Debug"
   * @param message a Message
   */
  public void examination(String message) {
    Log.d(logKey, message);
  }

  /**
   * "Debug"
   * @param message a Message
   * @param e An failure
   */
  public void examination(String message, Exception e) {
    Log.d(logKey, message, e);
  }

}

Aktivite kaydı yapan projenizde:

Logger log = new Logger("SuperLog");
// perform logging methods

"Logger" üzerinden kaydettiğiniz her şeyi yakalamak istediğinizde

LogCapture capture = Logger.getLogCat("main");

Acıktığınızda ve daha fazla kütük atıştırmak istediğinizde

LogCapture nextCapture = capture.getNextCapture();

Yakalamayı bir dize olarak alabilirsiniz.

String captureString = capture.toString();

Veya yakalamanın günlük öğelerini ile

String logItem = capture.log.get(itemNumber);

Yabancı günlük anahtarlarını yakalamanın kesin bir statik yöntemi yoktur, ancak hiçbiri daha azının bir yolu yoktur.

LogCapture foreignCapture = Logger.getLogCat("main", null, foreignCaptureKeyList);

Yukarıdakileri kullanmak aynı zamanda Logger.this.nextCaptureyabancı yakalamada arama yapmanıza da izin verecektir .


Bu, düşük ek yük [işlemde] stratejisi nedeniyle genellikle günlük kaydı ve analizi gerçekleştirmek için en iyi yöntemdir. Bu kodda bir hata olabilir veya olmayabilir. Zaman seçiminin logcat uygulaması, doğru bir eşleşme için verilen süreden daha büyük olmalıdır. Doğru bir zaman seçim algoritmasının olmaması, nextCapture'ın ilk öğesinde yinelenen bir günlük girişi oluşturacaktır.
Hypersoft Systems

Android-logcat'in zaman seçici seçeneğiyle ilişkili zaman biçimleri ve yerel ayarlarla ilgili dokümantasyon eksikliği, zaman biçimi-enterpolasyon-değişiklikleri gerektiren hatalar yaratmış olabilir.
Hypersoft Systems

Merhaba .. Kodunuzu kullandım ama sonuç her zaman boş. Hala geçerli?
img.simone

@ img.simone; Bunu kod revizyonlarımla güncelledim. Android'in logcat'i birkaç şekilde bozuldu. Birincisi, logcat'in tarih formatı çıktısının yıl bileşenine sahip olmamasıdır, bu da tarih karşılaştırmasını 1970 yılına geri döndürür; ikinci olarak, bir tarih içeren -t ve -T seçeneği, belirtilen tarihte günlükleri dışarı atmaya başlamaz, bu nedenle tarihi ayrıştırmalı ve 1970 yılına eşitlenmiş sayısal bir tarihle karşılaştırmalıyız. Bunu test edemem sizin için güncelleme, ancak kesinlikle işe yaramalı; kod, bu bağlama özgü değişikliklerle birlikte çalışan bir havuzdan gelir.
Hypersoft Systems

1
Sen çalışma kodunu bulabilirsiniz burada altında git.hsusa.core.log.controller.AndroidLogController.java; Bu "hızlı & kirli" çözüm yerine hscore kitaplığımı kullanmak isteyebilirsiniz. Hscore ile oturum açmak için: public final static SmartLogContext log = SmartLog.getContextFor("MyLogContext");başlamak için kullanmalısınız . Daha iyi bir API ile hemen hemen aynı şekilde çalışır. Bununla ilgili HERHANGİ bir yardıma ihtiyacınız olursa git hub sorun izleyicimi kullanabilirsiniz.
Hypersoft Systems

3

"-C" bayrağı arabelleği temizler.

-c Günlüğün tamamını temizler (temizler) ve çıkar.


yukarıdaki kodda -c nasıl kullanılır. günlükte bir şey bulursa onu temizlemek istiyorum
yuva ツ

yuva, sadece şunu yapın: process = Runtime.getRuntime (). exec ("logcat -c"); bufferedReader = new BufferedReader (yeni InputStreamReader (process.getInputStream ()), 1024); line = bufferedReader.readLine ();
djdance

1
            //CLEAR LOGS
            Runtime.getRuntime().exec("logcat -c");
            //LISTEN TO NEW LOGS
            Process pq=Runtime.getRuntime().exec("logcat v main");
            BufferedReader brq = new BufferedReader(new InputStreamReader(pq.getInputStream()));
            String sq="";
            while ((sq = brq.readLine()) != null)
            {
              //CHECK YOUR MSG HERE 
              if(sq.contains("send MMS with param"))
              {
              }
            }

Bunu uygulamamda kullanıyorum ve çalışıyor. Zamanlayıcı Görevi'nde yukarıdaki kodu kullanabilirsiniz, böylece ana iş parçacığınızı durdurmaz

        Timer t;
        this.t.schedule(new TimerTask()
        {
          public void run()
          {
            try
            {
                ReadMessageResponse.this.startRecord();//ABOVE METHOD HERE

            }
            catch (IOException ex)
            {
              //NEED TO CHECK SOME VARIABLE TO STOP MONITORING LOGS 
              System.err.println("Record Stopped");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            finally
            {
                ReadMessageResponse.this.t.cancel();
            }
          }
        }, 0L);
      }
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.