อ่าน logcat โดยใช้โปรแกรมภายในแอปพลิเคชัน


116

ฉันต้องการอ่านและตอบสนองต่อบันทึก logcat ภายในแอปพลิเคชันของฉัน

ฉันพบรหัสต่อไปนี้:

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) {}

รหัสนี้ส่งคืนบันทึก logcat ที่สร้างขึ้นจนกระทั่งแอปพลิเคชันเริ่มทำงาน -

แต่เป็นไปได้ไหมที่จะฟังบันทึก Logcat ใหม่ ๆ อย่างต่อเนื่อง?


1
อ็อพชัน -d จะดัมพ์บันทึกและออก เพียงแค่ลบตัวเลือก -d และ logcat จะไม่ออก
Frohnzie

1
ฉันจะล้างมันได้อย่างไร? - ฉันต้องการค้นหาบรรทัดเฉพาะเกี่ยวกับใบสมัครของฉัน
David

1
ไม่จำเป็นต้องรูท
Luis

2
หากไม่จำเป็นต้องรูทเฉพาะรุ่นการพัฒนาเท่านั้นที่สามารถเข้าถึงบันทึกของตัวเองได้? และรหัสนี้ถูกเรียกใช้ที่ไหน? ด้วยในแอปพลิเคชัน apk?
Ayyappa

2
ฉันลองทดสอบ ฉันสามารถอ่านเหตุการณ์ในกระบวนการของตัวเองได้เท่านั้น ฉันคิดว่าคุณต้องรูทเพื่ออ่านเหตุการณ์กระบวนการอื่น ๆ
Yetti99

คำตอบ:


55

คุณสามารถอ่านบันทึกต่อไปได้เพียงแค่ลบแฟล็ก "-d" ในโค้ดของคุณด้านบน

แฟล็ก "-d" สั่งให้ logcat แสดงเนื้อหาบันทึกและออก หากคุณลบแฟล็ก logcat จะไม่ยุติและยังคงส่งบรรทัดใหม่ที่เพิ่มเข้ามา

โปรดทราบว่าสิ่งนี้อาจบล็อกแอปพลิเคชันของคุณหากไม่ได้รับการออกแบบอย่างถูกต้อง

โชคดี.


หากฉันลบ "-d" แอปพลิเคชันที่ติดอยู่และฉันได้รับกล่องโต้ตอบบังคับปิด
เดวิด

21
ดังที่ได้กล่าวไปแล้วข้างต้นจะต้องมีการออกแบบแอปพลิเคชันที่รอบคอบ คุณต้องให้โค้ดด้านบนทำงานในเธรดแยกต่างหาก (เพื่อหลีกเลี่ยงการบล็อก UI) และในขณะที่คุณต้องการอัปเดต textview ใน UI ด้วยข้อมูลบันทึกคุณต้องใช้ Handler เพื่อโพสต์ข้อมูลกลับไปที่ UI
ลุย

2
สวัสดีคุณหลุยส์คุณช่วยโพสต์โค้ดตัวอย่างของเธรดที่แยกออกมาได้ไหม
img.simone

ดูคำตอบstackoverflow.com/a/59511458/1185087ซึ่งใช้โครูทีนซึ่งไม่บล็อกเธรด UI
user1185087

8

คุณสามารถล้าง logcat ของคุณด้วยวิธีนี้ฉันใช้เพื่อล้างหลังจากเขียน logcat ลงในไฟล์เพื่อหลีกเลี่ยงบรรทัดที่ซ้ำกัน:

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

ฉันเพิ่งค้นพบว่าการล้างบันทึกอาจใช้เวลาสักครู่ ดังนั้นหากคุณล้างบันทึกแล้วอ่านบันทึกทันทีรายการเก่าบางรายการอาจยังไม่ถูกล้าง นอกจากนี้รายการบันทึกที่เพิ่มใหม่บางรายการสามารถลบได้เนื่องจากมีการเพิ่มก่อนที่การล้างจะเสร็จสมบูรณ์ มันไม่ได้สร้างความแตกต่างแม้ว่าคุณจะเรียก process.waitfor ()
Tom Rutchik

6

ด้วย coroutines และไลบรารี lifecycle-liveata-ktxและlifecycle-viewmodel-ktxอย่างเป็นทางการมันง่ายอย่างนั้น:

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) }
        }
    }
}

การใช้

val logCatViewModel by viewModels<LogCatViewModel>()

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

ข้อเสนอแนะที่ดี ฉันสงสัยว่ามีวิธีที่จะทำให้งานนี้WebViewแทนTextViewด้วย
Fatih

4

นี่คือการรวบรวม / ดร็อปอินด่วนที่สามารถใช้ในการบันทึกรายการบันทึกปัจจุบันทั้งหมดหรือใหม่ทั้งหมด (ตั้งแต่คำขอล่าสุด)

คุณควรแก้ไข / ขยายสิ่งนี้เนื่องจากคุณอาจต้องการส่งคืนสตรีมแบบต่อเนื่องแทนที่จะเป็น LogCapture

"คู่มือ" ของ Android LogCat: 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);
  }

}

ในโครงการของคุณซึ่งดำเนินการบันทึกกิจกรรม:

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

เมื่อคุณต้องการบันทึกทุกสิ่งที่คุณเข้าสู่ระบบผ่าน "Logger"

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

เมื่อคุณหิวและอยากทานของว่างบนท่อนไม้มากขึ้น

LogCapture nextCapture = capture.getNextCapture();

คุณสามารถจับภาพเป็นสตริงด้วย

String captureString = capture.toString();

หรือคุณสามารถรับรายการบันทึกจากการจับภาพด้วย

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

ไม่มีวิธีการคงที่แน่นอนในการจับคีย์บันทึกแปลกปลอม แต่มีวิธีที่ไม่น้อยไปกว่ากัน

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

นอกจากนี้การใช้ข้างต้นจะช่วยให้คุณสามารถเรียกร้องLogger.this.nextCaptureให้มีการจับกุมชาวต่างชาติได้


โดยทั่วไปเป็นวิธีที่ดีที่สุดในการบันทึกและวิเคราะห์เนื่องจากกลยุทธ์ [ในการประมวลผล] ที่มีค่าใช้จ่ายต่ำ รหัสนี้อาจมีหรือไม่มีก็ได้ Logcat การเลือกเวลาจะต้องมากกว่าเวลาที่กำหนดสำหรับการจับคู่ที่ถูกต้อง การขาดอัลกอริทึมการเลือกเวลาที่ถูกต้องจะสร้างรายการบันทึกที่ซ้ำกันในองค์ประกอบแรกของ nextCapture
Hypersoft Systems

การขาดเอกสารเกี่ยวกับรูปแบบเวลาและสถานที่ที่เกี่ยวข้องกับตัวเลือกตัวเลือกเวลาของ android-logcat อาจทำให้เกิดข้อบกพร่องซึ่งจะต้องมีการแก้ไขรูปแบบเวลา
Hypersoft Systems

สวัสดี .. ฉันใช้รหัสของคุณ แต่ผลลัพธ์มักจะว่างเปล่า ยังใช้ได้อยู่ไหม
img.simone

@ img.simone; ฉันได้อัปเดตสิ่งนี้ด้วยการแก้ไขโค้ดของฉัน Logcat ของ Android เสียไม่กี่วิธี ประการแรกคือเอาต์พุตรูปแบบวันที่ของ logcat ไม่มีองค์ประกอบของปีซึ่งทำให้การเปรียบเทียบวันที่ย้อนกลับไปเป็นปี 1970 ประการที่สองตัวเลือก -t และ -T ที่มีวันที่ไม่ได้เริ่มคายบันทึกตามวันที่ที่ระบุดังนั้นเราจึงต้องแยกวิเคราะห์วันที่และเปรียบเทียบกับวันที่ที่เป็นตัวเลขที่ซิงโครไนซ์กับปี 1970 ฉันไม่สามารถทดสอบสิ่งนี้ได้ อัปเดตสำหรับคุณ แต่ควรใช้งานได้แน่นอน เนื่องจากรหัสมาจากที่เก็บที่ใช้งานได้พร้อมการแก้ไขเฉพาะสำหรับบริบทนี้
Hypersoft Systems

1
คุณสามารถค้นหารหัสการทำงานได้ที่นี่ภายใต้git.hsusa.core.log.controller.AndroidLogController.java; คุณอาจต้องการใช้ไลบรารี hscore ของฉันแทนโซลูชัน "ด่วนและสกปรก" นี้ ในการบันทึกด้วย hscore คุณต้องใช้: public final static SmartLogContext log = SmartLog.getContextFor("MyLogContext");เพื่อเริ่มต้น มันทำงานในลักษณะเดียวกันกับ API ที่ดีกว่า คุณสามารถใช้ตัวติดตามปัญหา git hub ของฉันได้หากคุณต้องการความช่วยเหลือใด ๆ
Hypersoft Systems

3

แฟล็ก "-c" จะล้างบัฟเฟอร์

-c ล้าง (ล้าง) บันทึกทั้งหมดและออก


วิธีใช้ -c ในโค้ดด้านบนหากพบบางสิ่งในบันทึกฉันต้องการล้างมัน
yuva ツ

yuva ก็แค่ทำ: process = Runtime.getRuntime (). exec ("logcat -c"); bufferedReader = BufferedReader ใหม่ (InputStreamReader ใหม่ (process.getInputStream ()), 1024); บรรทัด = 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"))
              {
              }
            }

ฉันใช้สิ่งนี้ในแอพของฉันและมันก็ใช้ได้ และคุณสามารถใช้โค้ดด้านบนใน Timer Task เพื่อที่จะไม่หยุดเธรดหลักของคุณ

        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);
      }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.