Dzienniki zapisu systemu Android do pliku tekstowego

129

Próbuję zapisywać dzienniki w niestandardowym pliku Log.txt w pliku systemu Android przy użyciu tego mojego kodu, ale ta metoda tworzy plik, ale nic nie zawiera. Zasadniczo chcę przeczytać poprzednią zawartość pliku, a następnie dołączyć moje dane do istniejącej zawartości.

Kodeks wygląda następująco:

public static void write(String str) 
    {
        InputStream fileInputStream = null;
        FileOutputStream fileOutpurStream = null;
        try
        { 
            fileInputStream = new FileInputStream(file);
            fileOutpurStream = new FileOutputStream(file);
            if(file.exists())
            {
                int ch = 0;
                int current = 0;
                StringBuffer buffer = new StringBuffer();
                while((ch = fileInputStream.read()) != -1)
                {
                    buffer.append((char) ch);
                    current++;
                }
                byte data[]=new byte[(int)file.length()];
                fileInputStream.read(data);   
                fileOutpurStream.write(data);
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            } 
            else
            {   
                file.createNewFile();
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                fileInputStream.close();
                fileOutpurStream.flush();
                fileOutpurStream.close();
                fileOutpurStream = null;
                fileInputStream = null;
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
y ramesh rao
źródło

Odpowiedzi:

247

Mam nadzieję, że to pomoże ...

public void appendLog(String text)
{       
   File logFile = new File("sdcard/log.file");
   if (!logFile.exists())
   {
      try
      {
         logFile.createNewFile();
      } 
      catch (IOException e)
      {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }
   try
   {
      //BufferedWriter for performance, true to set append to file flag
      BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
      buf.append(text);
      buf.newLine();
      buf.close();
   }
   catch (IOException e)
   {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
}
outkkast
źródło
83
Nie zapomnij dodać pozwolenia na write_external_storage w Manifest!
virusss 8
5
Musiałem dodać buf.flush (); beforebuf.close (); ale ta funkcja była dokładnie tym, czego potrzebowałem. dzięki
Csabi
1
skąd mam wywołać tę funkcję, aby zapisywała plik logowania całej aplikacji ???
uniruddh
10
Zalecałbym przebudowę kodu tak, aby znajdował się buf.close()wewnątrz finallybloku.
William Price
2
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />było oczywiście tym, co oznaczało @ virusss8.
Bengt
29

Dla tych, którzy są nowicjuszami w logowaniu w Javie i rejestrowaniu w systemie Android

  1. Log4j to ogólna implementacja logowania w Javie, która jest teraz projektem fundacji oprogramowania Apache. Nie jest specyficzny dla Androida, więc ma pewne niezgodności z Androidem.
  2. SL4J nie jest implementacją logowania, jest warstwą abstrakcji. Pomaga to uniknąć sytuacji, takich jak zależności każdej biblioteki innej firmy od projektu, próbując użyć własnej implementacji rejestrowania, takiej jak Log4j. Źródło .

Poniżej przedstawiono niektóre opcje logowania do txt w systemie Android

  1. Użyj logcat -fjak w tej odpowiedzi, aby zalogować się do pliku. Zauważ, że od Androida 4.2 uprawnienie READ_LOGS nie ma żadnego wpływu i każda aplikacja (chyba że telefon jest zrootowana) może odczytywać tylko własne dzienniki. Wadą jest to, że bufor logcat jest cykliczny i ma limit rozmiaru. Możesz nie otrzymać wcześniejszych dzienników.
  2. Użyj microlog4android (napisanego dla urządzeń mobilnych, takich jak Android), jak we wcześniejszej odpowiedzi . Mógłby być sposób, ale nie mogłem wymyślić, jak używać microlog4Android do logowania się do wewnętrznej pamięci aplikacji. Jedyną opcją dla ścieżki dzienników była pamięć zewnętrzna, taka jak sdcard, więc nie mogłem jej użyć.
  3. Użyj Log4j z android-logging-log4j . Co robi android-logging-log4j? Ułatwia korzystanie z Log4j w systemie Android, zapewniając dwie funkcje.

    • opcja wysyłania dzienników do logcat oprócz pliku logowania
    • prosty sposób na ustawienie opcji konfiguracyjnych Log4j, takich jak ścieżka do pliku, maksymalny rozmiar pliku, liczba kopii zapasowych itp., poprzez dostarczenie klasy LogConfigurator.

    Prosty przykład poniżej. Zauważ, że loggerobiekt w poniższym przykładzie jest zwrócony obiektem Log4j, a nie klasą android-logging-log4j. Dlatego android-logging-log4j jest używany tylko do konfigurowania Log4j.

  4. Jeszcze spróbować LogBack . LogBack został opracowany przez tę samą osobę, która wymyśliła biblioteki Log4J 1.xi SL4J. Nie jest to jednak związane z Log4j 2.x.

Kroki korzystania z Log4j w systemie Android.

  1. Dodaj zarówno log4j-1.2.x.jar, jak i android-logging-log4j-1.0.3.jar do folderu libs.

  2. Dodawaj uprawnienia tylko w przypadku korzystania z pamięci zewnętrznej
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  3. Napisz Log4jklasę pomocniczą

    package com.example.logger;
    
    import android.os.Environment;
    import de.mindpipe.android.logging.log4j.LogConfigurator;
    
    public class Log4jHelper {
        private final static LogConfigurator mLogConfigrator = new LogConfigurator();
    
        static {
            configureLog4j();
        }
    
        private static void configureLog4j() {
            String fileName = Environment.getExternalStorageDirectory() + "/" + "log4j.log";
            String filePattern = "%d - [%c] - %p : %m%n";
            int maxBackupSize = 10;
            long maxFileSize = 1024 * 1024;
    
            configure( fileName, filePattern, maxBackupSize, maxFileSize );
        }
    
        private static void configure( String fileName, String filePattern, int maxBackupSize, long maxFileSize ) {
            mLogConfigrator.setFileName( fileName );
            mLogConfigrator.setMaxFileSize( maxFileSize );
            mLogConfigrator.setFilePattern(filePattern);
            mLogConfigrator.setMaxBackupSize(maxBackupSize);
            mLogConfigrator.setUseLogCatAppender(true);
            mLogConfigrator.configure();
    
        }
    
        public static org.apache.log4j.Logger getLogger( String name ) {
            org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger( name );
            return logger;
        }
    }
  4. W klasie Activity

    org.apache.log4j.Logger log= Log4jHelper.getLogger( "YourActivity" );
    log.error("Error");
    log.info("Info");
    log.warn("Warn");

Przykładowe źródło . Zauważ, że log4j 2.x (ulepszone funkcje) przepisane od nowa nie jest wstecznie kompatybilne z log4j 1.x. Więc musisz użyć log4j 1.2.x jar z android-logging-log4j jar. Udało mi się zalogować do wewnętrznego pliku aplikacji, a później wysłać go e-mailemsetReadable(true, false)

Kiran
źródło
24

microlog4android działa dla mnie, ale dokumentacja jest dość uboga. Wszystko, co muszą dodać, to samouczek szybkiego startu .

Oto krótki samouczek, który znalazłem.

  1. Dodaj następującą zmienną statyczną do swojej głównej aktywności:

    private static final Logger logger = LoggerFactory.getLogger();
  2. Dodaj następujące elementy do swojej onCreate()metody:

    PropertyConfigurator.getConfigurator(this).configure();
  3. Utwórz plik o nazwie microlog.propertiesi zapisz go w assetskatalogu

  4. Edytuj microlog.propertiesplik w następujący sposób:

    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  5. Dodaj takie instrukcje logowania:

    logger.debug("M4A");

Dla każdej klasy tworzysz obiekt rejestrujący, jak określono w 1)

6. Możesz dodać następujące uprawnienia:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Oto źródło samouczka

Henry Bennett
źródło
4
FileAppender utworzy plik „microlog.txt” na twojej karcie SD (pełna ścieżka w moim przypadku to „/sdcard/microlog.txt).
Ruslan Yanchyshyn
2
Ten krótki samouczek powinien być częścią oficjalnej dokumentacji Microlog4Android.
Johan Karlsson
Błąd: Android Dex: [projekt] com.android.dex.DexException: wiele plików dex definiuje Lcom / google / code / microlog4android / Level; ?
10

Ostrzeżenie: Mogę cię całkowicie nie rozumieć, ale jeśli chcesz tylko pliku dziennika, po co się przejmować?

Umieść to w pliku bat (zmień ścieżkę do katalogu narzędzi, a twoja nazwa aplikacji to oczywiście nazwa twojej aplikacji):

cd "C:\devAndroid\Software\android-sdk-windows-1.6_r1\android-sdk-windows-1.6_r1\tools"
adb logcat -v time   ActivityManager:W  yourappname:D  *:W >"C:\devAndroid\log\yourappname.log"

Następnie w swoim kodzie zrób coś podobnego do tego:

Log.d("yourappname", "Your message");

Aby utworzyć dziennik, podłącz kabel USB i uruchom plik bat.

pozdrowienia

BeMeCollective
źródło
Nie zapomnij zaimportować android.util.Log.
Spidey
Zwraca „błąd: więcej niż jedno urządzenie i emulator - oczekiwanie na urządzenie -” i nic więcej. Coś nie tak?
eros
20
Jak to działa, jeśli podczas uruchamiania aplikacji nie ma Cię w pobliżu komputera?
DDSports
@DDSports nie. Ale nie rozumiał istoty pytania
Ewoks
@DDSports możesz używać adb przez wifi.
Daniel F
8

Użyj slf4android lib.
Jest to prosta implementacja interfejsu API slf4j przy użyciu java.util.logging systemu Android. *.

Cechy:

  • logowanie do pliku po wyjęciu z pudełka
  • logowanie do dowolnego innego miejsca docelowego przez LoggerConfiguration.configuration().addHandlerToLogger
  • potrząśnij urządzeniem, aby wysłać dzienniki ze zrzutem ekranu pocztą elektroniczną
  • naprawdę mały, to tylko ~ 55kB

slf4android jest utrzymywany głównie przez @miensol .

Przeczytaj więcej o slf4android na naszym blogu:

klimat
źródło
7

Powinieneś rzucić okiem na microlog4android. Mają rozwiązanie gotowe do zalogowania się do pliku.

http://code.google.com/p/microlog4android/

darius
źródło
12
Wydaje się, że to dobra biblioteka, ale dokumentacja jest okropna. Po prostu nie mogłem wymyślić, jak sprawić, by to zadziałało i skończyło się na tym, że sam coś złożyłem.
Paul Lammertsma,
@PaulLammertsma: Myślę, że byłoby miło, gdybyś wsparł Microlog4Android. FYI: ma to samo API co Log4j. Przepraszamy za złą dokumentację.
Johan Karlsson
@Paul Lammertsma Jak COŚ może być dobre, jeśli dokumentacja jest tak zła, że ​​nie możesz jej użyć? Jeśli nie możesz zmusić go do pracy, to bzdura.
Niesamowity
7

To może być późno, ale mam nadzieję, że to pomoże. Spróbuj tego ....

public void writefile()
    {
        File externalStorageDir = Environment.getExternalStorageDirectory();
        File myFile = new File(externalStorageDir , "yourfilename.txt");

        if(myFile.exists())
        {
           try
           {

        FileOutputStream fostream = new FileOutputStream(myFile);
        OutputStreamWriter oswriter = new OutputStreamWriter(fostream); 
        BufferedWriter bwriter = new BufferedWriter(oswriter);   
        bwriter.write("Hi welcome ");
        bwriter.newLine();            
        bwriter.close(); 
        oswriter.close(); 
        fostream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
        else
        {
            try {
                myFile.createNewFile();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }

tutaj bfwritter.newlinezapisuje twój tekst do pliku. I dodaj pozwolenie

 <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>

w pliku manifestu bezbłędnie.

AndroidOptimist
źródło
6

Rozwiązałem ten problem za pomocą następującego fragmentu kodu w linii poleceń:

File outputFile = new File("pathToFile"); 
Runtime.getRuntime().exec("logcat -c");
Runtime.getRuntime().exec("logcat -v time -f " + outputFile.getAbsolutePath())

Gdzie opcja „czas” dodaje szczegóły pola metadanych dla daty, czasu wywołania, priorytetu / tagu i PID procesu wysyłającego komunikat.

Następnie w swoim kodzie zrób coś podobnego do tego (używając android.util.Log):

Log.d("yourappname", "Your message");
Nova
źródło
4
Działa ładnie, gdy adbjest podłączony, ale nie działa, gdy urządzenie jest w trybie autonomicznym. Nie użyłbym go w produkcji, ale jest to proste rozwiązanie w trybie debugowania.
Julien Kronegg
2

Ogólnie rzecz biorąc, musisz mieć uchwyt pliku przed otwarciem strumienia. Masz uchwyt fileOutputStream przed createNewFile () w bloku else. Strumień nie tworzy pliku, jeśli nie istnieje.

Niezbyt specyficzne dla Androida, ale to dużo IO w tym celu. Co się stanie, jeśli wykonasz wiele operacji „zapisywania” jedna po drugiej? Będziesz czytać całą zawartość i pisać całą zawartość, zajmując trochę czasu, a co ważniejsze, żywotność baterii.

Sugeruję użycie java.io.RandomAccessFile, szukanie () 'do końca, a następnie writeChars (), aby dołączyć. Będzie to znacznie czystszy kod i prawdopodobnie znacznie szybszy.

Nate
źródło
2

Stworzyłem prostą, lekką klasę (około 260 LoC), która rozszerza standardową implementację android.util.Log z logowaniem opartym na plikach:
Każda wiadomość dziennika jest rejestrowana przez android.util.Log, a także zapisywana w pliku tekstowym na urządzeniu.

Możesz go znaleźć na github:
https://github.com/volkerv/FileLog

Volker Voecking
źródło
1
czy nie, musimy upewnić się, że operacje na plikach nie są wykonywane w wątku interfejsu użytkownika. O ile mamy ogromną ilość rejestrowanych plików?
Jayshil Dave
2

Po długich badaniach stwierdziłem, że:

  • android.util.Log domyślne użycie java.util.logging.Logger
  • LogCat używa loggerz nazwą "", aby uzyskać wystąpienie jego użyciaLogManager.getLogManager().getLogger("")
  • Urządzenia z systemem Android dodaje do loggerwystąpienia LogCat com.android.internal.logging.AndroidHandlerpo uruchomieniu aplikacji do debugowania
  • Ale!!! com.android.internal.logging.AndroidHandlerwypisuje komunikaty do logcat tylko z poziomami wyższymi java.util.logging.Level.INFOniż ( Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF)

Aby zapisywać logi do pliku, wystarczy rootLogger "" dodać java.util.logging.FileHandler:

  class App : Application{
    override fun onCreate() {
      super.onCreate()
      Log.d(TAG, printLoggers("before setup"))

      val rootLogger = java.util.logging.LogManager.getLogManager().getLogger("")
      val dirFile = destinationFolder
      val file = File(dirFile,"logFile.txt")
      val handler = java.util.logging.FileHandler(file.absolutePath, 5* 1024 * 1024/*5Mb*/, 1, true)
      handler.formatter = AndroidLogFormatter(filePath = file.absolutePath)

      rootLogger?.addHandler(handler)

      Log.d(TAG, printLoggers("after setup"))
    }
  }

val destinationFolder: File
        get() {
            val parent = 
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile
            val destinationFolder = File(parent, "MyApp")
            if (!destinationFolder.exists()) {
                destinationFolder.mkdirs()
                destinationFolder.mkdir()
            }
            return destinationFolder
        }
class AndroidLogFormatter(val filePath: String = "", var tagPrefix: String = "") : Formatter() {

    override fun format(record: LogRecord): String {
        val tag = record.getTag(tagPrefix)
        val date = record.getDate()
        val level = record.getLogCatLevel()
        val message = record.getLogCatMessage()
        return "$date $level$tag: $message\n"
    }
}

fun LogRecord.getTag(tagPrefix: String): String {
    val name = loggerName
    val maxLength = 30
    val tag = tagPrefix + (if (name.length > maxLength) name.substring(name.length - maxLength) else name)
    return tag
}

fun LogRecord.getDate(): String? {
    return Date(millis).formatedBy("yyyy-MM-dd HH:mm:ss.SSS")
}

fun Date?.formatedBy(dateFormat: String): String? {
    val date = this
    date ?: return null
    val writeFormat = SimpleDateFormat(dateFormat, Locale.getDefault()) //MM в HH:mm
    return writeFormat.format(date)
}

fun LogRecord.getLogCatMessage(): String {
    var message = message

    if (thrown != null) {
        message += Log.getStackTraceString(thrown)
    }
    return message
}

fun Int.getAndroidLevel(): Int {
    return when {
        this >= Level.SEVERE.intValue() -> { // SEVERE
            Log.ERROR
        }
        this >= Level.WARNING.intValue() -> { // WARNING
            Log.WARN
        }
        this >= Level.INFO.intValue() -> { // INFO
            Log.INFO
        }
        else -> {
            Log.DEBUG
        }
    }
}

fun LogRecord.getLogCatLevel(): String {
    return when (level.intValue().getAndroidLevel()) {
        Log.ERROR -> { // SEVERE
            "E/"
        }
        Log.WARN -> { // WARNING
            "W/"
        }
        Log.INFO -> { // INFO
            "I/"
        }
        Log.DEBUG -> {
            "D/"
        }
        else -> {
            "D/"
        }
    }
}

fun getLoggerLevel(level: Int): Level {
    return when (level) {
        Log.ERROR -> { // SEVERE
            Level.SEVERE
        }
        Log.WARN -> { // WARNING
            Level.WARNING
        }
        Log.INFO -> { // INFO
            Level.INFO
        }
        Log.DEBUG -> {
            Level.FINE
        }
        else -> {
            Level.FINEST
        }
    }
}

Aby wydrukować wszystkie rejestratory w swojej aplikacji, użyj:

Log.e(TAG, printLoggers("before setup"))

 private fun printLoggers(caller: String, printIfEmpty: Boolean = true): String {
        val builder = StringBuilder()
        val loggerNames = LogManager.getLogManager().loggerNames
        builder.appendln("--------------------------------------------------------------")
        builder.appendln("printLoggers: $caller")
        while (loggerNames.hasMoreElements()) {
            val element = loggerNames.nextElement()
            val logger = LogManager.getLogManager().getLogger(element)
            val parentLogger: Logger? = logger.parent
            val handlers = logger.handlers
            val level = logger?.level
            if (!printIfEmpty && handlers.isEmpty()) {
                continue
            }
            val handlersNames = handlers.map {
                val handlerName = it.javaClass.simpleName
                val formatter: Formatter? = it.formatter
                val formatterName = if (formatter is AndroidLogFormatter) {
                    "${formatter.javaClass.simpleName}(${formatter.filePath})"
                } else {
                    formatter?.javaClass?.simpleName
                }
                "$handlerName($formatterName)"
            }
            builder.appendln("level: $level logger: \"$element\" handlers: $handlersNames parentLogger: ${parentLogger?.name}")
        }
        builder.appendln("--------------------------------------------------------------")
        return builder.toString()
    }
NickUnuchek
źródło
Cześć. Jakie są korzyści z używania tego rejestratora. Nie widzę różnicy w przypadku niestandardowego rejestratora. czy coś mi brakuje?
Abins Shaji
1

Ten wariant jest znacznie krótszy

próbować {
    Final File path = nowy plik (
            Environment.getExternalStorageDirectory (), "DBO_logs5");
    if (! path.exists ()) {
        path.mkdir ();
    }
    Runtime.getRuntime (). Exec (
            "logcat -d -f" + ścieżka + separator pliku
                    + „dbo_logcat”
                    + „.txt”);
} catch (IOException e) {
    e.printStackTrace ();
}
xoxol_89
źródło
1

Możesz skorzystać z biblioteki, którą napisałem. Jest bardzo łatwy w użyciu:

Dodaj tę zależność do swojego pliku gradle:

dependencies {
    compile 'com.github.danylovolokh:android-logger:1.0.2'
}

Zainicjuj bibliotekę w klasie Application:

File logsDirectory = AndroidLogger.getDefaultLogFilesDirectory(this);
    int logFileMaxSizeBytes = 2 * 1024 * 1024; // 2Mb
    try {
        AndroidLogger.initialize(
                this,
                logsDirectory,
                "Log_File_Name",
                logFileMaxSizeBytes,
                false
                );
    } catch (IOException e) {
        // Some error happened - most likely there is no free space on the system
    }

Oto jak korzystasz z biblioteki:

AndroidLogger.v("TAG", "Verbose Message");

A oto jak odzyskać logi:

AndroidLogger.processPendingLogsStopAndGetLogFiles(new AndroidLogger.GetFilesCallback() {
        @Override
        public void onFiles(File[] logFiles) {
            // get everything you need from these files
            try {
                AndroidLogger.reinitAndroidLogger();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

Oto link do strony github z dodatkowymi informacjami: https://github.com/danylovolokh/AndroidLogger

Mam nadzieję, że to pomoże.

Danylo Volokh
źródło
1

Wiele poprzednich wersji log4j nie działa teraz (05/2019). Ale możesz użyć Hyperlog - mogę potwierdzić, że działa.

  1. Dodaj tę linię do swojego projektu zależności i synchronizacji

    implementation 'com.hypertrack:hyperlog:0.0.10'
  2. Utwórz nową klasę aplikacji (utwórz nową klasę Java i rozszerz aplikację). Następnie w metodzie onCreate dodaj te linie:

    HyperLog.initialize(this);
    HyperLog.setLogLevel(Log.VERBOSE);
    
    HyperLog.getDeviceLogsInFile(this);
  3. Zmień plik manifestu, aby zdefiniować plik aplikacji.

    <application
        android:name=".AppClass"
        .....
  4. Różne sposoby logowania:

    HyperLog.d(TAG,"debug");
    HyperLog.i(TAG,"information");
    HyperLog.e(TAG,"error");
    HyperLog.v(TAG,"verbose");
    HyperLog.w(TAG,"warning");
    HyperLog.a(TAG,"assert");
    HyperLog.exception(TAG,"exception",throwable);
  5. Znajdź swoje pliki dziennika. Nawigować do

    RootFolder/android/data/"appPackageName/LogFiles/
Haider Malik
źródło
Wypróbowałem tę bibliotekę w pliku wygenerowanym za pomocą HyperLog.getDeviceLogsInFile (this); jest tam tylko ostatni wygenerowany dziennik
mad_greasemonkey