Écriture de journaux Android dans un fichier texte

128

J'essaie d'écrire des journaux dans un fichier Log.txt personnalisé sur un fichier Android en utilisant ce code de Mine, mais cette méthode crée un fichier mais ne contient rien. Fondamentalement, je veux lire le contenu précédent du fichier, puis ajouter mes données au contenu existant.

Le code est comme suit :

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
la source

Réponses:

247

J'espère que cela peut vous aider ...

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
la source
82
N'oubliez pas d'ajouter la permission pour writing_external_storage dans Manifest!
virusss8
5
J'avais besoin d'ajouter buf.flush (); beforebuf.close (); mais cette fonction était exactement ce dont j'avais besoin. merci
Csabi
1
d'où dois-je appeler cette fonction pour qu'elle écrive le journal de toutes les applications dans le fichier ???
uniruddh le
10
Je recommanderais de restructurer le code afin qu'il buf.close()soit à l'intérieur d'un finallybloc.
William Price
2
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />était ce que @ virusss8 voulait dire, bien sûr.
Bengt
29

Pour ceux qui découvrent la journalisation Java en général et la journalisation Android

  1. Log4j est une implémentation générique de journalisation Java et est maintenant un projet de la fondation logicielle Apache. Il n'est pas spécifique à Android et présente donc des incompatibilités avec Android.
  2. SL4J n'est pas une implémentation de journalisation, c'est une couche d'abstraction. Cela permet d'éviter des situations telles que, chaque dépendance de bibliothèque tierce à un projet, essayant d'utiliser sa propre implémentation de journalisation comme Log4j. Source .

Certaines options de connexion au txt sous Android sont ci-dessous

  1. Utilisez logcat -fcomme dans cette réponse pour vous connecter au fichier. Notez qu'à partir d'Android 4.2, l'autorisation READ_LOGS n'a aucun impact et chaque application (sauf si le téléphone est enraciné) ne peut lire que ses propres journaux. L'inconvénient ici est que le tampon logcat est circulaire et a une limite de taille. Vous pourriez ne pas obtenir les journaux précédents.
  2. Utilisez microlog4android (écrit pour les appareils mobiles comme Android) comme dans la réponse précédente . Il pourrait y avoir un moyen, mais je ne pouvais pas comprendre, comment utiliser microlog4Android pour se connecter au stockage interne de l'application. La seule option pour le chemin des journaux était le stockage externe comme sdcard et je ne pouvais donc pas l'utiliser.
  3. Utilisez Log4j avec android-logging-log4j . Que fait android-logging-log4j? Il rend Log4j plus facile à utiliser sous Android en donnant deux fonctions.

    • option pour envoyer les journaux à logcat en plus du fichier de journalisation
    • un moyen simple de définir les options de configuration de Log4j telles que le chemin du fichier, la taille maximale du fichier, le nombre de sauvegardes, etc. en fournissant la classe LogConfigurator.

    Exemple simple ci-dessous. Notez que l' loggerobjet dans l'exemple ci-dessous est un objet Log4j renvoyé et non une classe android-logging-log4j. Ainsi, android-logging-log4j est utilisé uniquement pour configurer Log4j.

  4. Pourtant, pour essayer LogBack . LogBack est développé par la même personne qui a créé les bibliothèques Log4J 1.x et SL4J. Pas lié à Log4j 2.x cependant.

Étapes d'utilisation de Log4j sous Android.

  1. Ajoutez à la fois log4j-1.2.x.jar et android-logging-log4j-1.0.3.jar au dossier libs.

  2. Ajouter des autorisations uniquement si vous utilisez un stockage externe
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  3. Écrire une Log4jclasse d'assistance

    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. En classe d'activité

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

Exemple de source . Notez que log4j 2.x (fonctionnalités améliorées) réécrit à partir de zéro n'est pas compatible avec log4j 1.x. Vous devez donc utiliser le jar log4j 1.2.x avec le jar android-logging-log4j. J'ai pu me connecter au fichier interne de l'application et plus tard envoyer le fichier avecsetReadable(true, false)

Kiran
la source
24

microlog4android fonctionne pour moi mais la documentation est assez pauvre. Tout ce qu'ils doivent ajouter est un tutoriel de démarrage rapide .

Voici un petit tutoriel que j'ai trouvé.

  1. Ajoutez la variable statique suivante dans votre activité principale:

    private static final Logger logger = LoggerFactory.getLogger();
  2. Ajoutez ce qui suit à votre onCreate()méthode:

    PropertyConfigurator.getConfigurator(this).configure();
  3. Créez un fichier nommé microlog.propertieset stockez-le dans le assetsrépertoire

  4. Modifiez le microlog.propertiesfichier comme suit:

    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  5. Ajoutez des instructions de journalisation comme celle-ci:

    logger.debug("M4A");

Pour chaque classe, vous créez un objet enregistreur comme spécifié en 1)

6.Vous pouvez ajouter l'autorisation suivante:

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

Voici la source du tutoriel

Henry Bennett
la source
4
FileAppender créera un fichier "microlog.txt" sur votre carte SD (le chemin complet dans mon cas est "/sdcard/microlog.txt).
Ruslan Yanchyshyn
2
Ce tutoriel rapide devrait faire partie de la documentation officielle de Microlog4Android.
Johan Karlsson
Erreur: Android Dex: [projet] com.android.dex.DexException: plusieurs fichiers dex définissent Lcom / google / code / microlog4android / Level; ?
10

Attention: je vous comprends peut-être totalement, mais si vous ne voulez qu'un fichier journal, pourquoi transpirer?

Mettez ceci dans un fichier chauve-souris (changez le chemin vers votre répertoire d'outils, et yourappname est bien sûr le nom de votre application):

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"

Ensuite, dans votre code, faites quelque chose de similaire à ceci:

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

Pour créer le journal, connectez le câble USB et exécutez votre fichier bat.

Cordialement

BeMeCollective
la source
N'oubliez pas d'importer android.util.Log.
Spidey
Il renvoie "erreur: plus d'un périphérique et émulateur - en attente d'un périphérique -" et rien de plus. Quelque chose ne va pas?
eros
20
Comment cela fonctionne-t-il si vous n'êtes pas à proximité d'un PC lors de l'exécution de l'application?
DDSports
@DDSports ce n'est pas le cas. Mais il n'a pas compris l'essence de la question
Ewoks
@DDSports, vous pouvez utiliser adb via wifi.
Daniel F
8

Utilisez slf4android lib.
C'est une implémentation simple de l' api slf4j en utilisant android java.util.logging. *.

Fonctionnalités:

  • connexion au fichier hors de la boîte
  • se connecter à toute autre destination en LoggerConfiguration.configuration().addHandlerToLogger
  • secouez votre appareil pour envoyer des journaux avec capture d'écran par e-mail
  • vraiment petit, il n'a fallu que ~ 55 Ko

slf4android est maintenu principalement par @miensol .

En savoir plus sur slf4android sur notre blog:

Klimat
la source
7

Vous devriez jeter un oeil à microlog4android. Ils ont une solution prête à se connecter à un fichier.

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

Darius
la source
12
Cela semble être une bonne bibliothèque, mais la documentation est terrible. Je ne savais tout simplement pas comment le faire fonctionner et j'ai fini par assembler quelque chose moi-même.
Paul Lammertsma
@PaulLammertsma: Je pense que ce serait bien que vous ayez contribué à Microlog4Android à la place. FYI: il a la même API que Log4j. Désolé pour la mauvaise documentation.
Johan Karlsson
@Paul Lammertsma Comment RIEN pourrait-il être bon si sa documentation est si mauvaise que vous ne pouvez pas l'utiliser? Si vous ne pouvez pas le faire fonctionner, c'est de la merde.
L'incroyable janvier
7

C'est peut-être tard, mais j'espère que cela vous aidera. Essayez ceci ...

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

ici bfwritter.newlineécrit votre texte dans le fichier. Et ajoutez la permission

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

dans votre fichier manifeste sans faute.

AndroidOptimist
la source
6

J'ai résolu ce problème avec le morceau de code suivant en ligne de commande:

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

Où l'option "heure" ajoute des détails de champ de métadonnées pour la date, l'heure d'appel, la priorité / étiquette et le PID du processus émettant le message.

Ensuite, dans votre code, faites quelque chose de similaire à ceci (en utilisant android.util.Log):

Log.d("yourappname", "Your message");
Nova
la source
4
Fonctionne bien lorsqu'il adbest connecté, mais ne fonctionne pas lorsque l'appareil est en mode autonome. Je ne l'utiliserais pas en production, mais c'est une solution simple en mode débogage.
Julien Kronegg
2

En général, vous devez disposer d'un descripteur de fichier avant d'ouvrir le flux. Vous avez un handle fileOutputStream avant createNewFile () dans le bloc else. Le flux ne crée pas le fichier s'il n'existe pas.

Pas vraiment spécifique à Android, mais c'est beaucoup d'E / S à cet effet. Et si vous effectuez plusieurs opérations "d'écriture" l'une après l'autre? Vous lirez l'intégralité du contenu et rédigerez l'intégralité du contenu, en prenant du temps et, plus important encore, l'autonomie de la batterie.

Je suggère d'utiliser java.io.RandomAccessFile, seek () 'ing jusqu'à la fin, puis writeChars () pour ajouter. Ce sera un code beaucoup plus propre et probablement beaucoup plus rapide.

Nate
la source
2

J'ai créé une classe simple et légère (environ 260 LoC) qui étend l'implémentation standard android.util.Log avec la journalisation basée sur les fichiers:
chaque message de journal est enregistré via android.util.Log et également écrit dans un fichier texte sur l'appareil.

Vous pouvez le trouver sur github:
https://github.com/volkerv/FileLog

Volker Voecking
la source
1
n'est-ce pas une chose dont nous avons besoin pour nous assurer que les opérations sur les fichiers ne sont pas effectuées sur le thread de l'interface utilisateur. Dans le cas où nous aurions une énorme quantité de journalisation de fichiers?
Jayshil Dave
2

Après une longue enquête, j'ai constaté que:

  • android.util.Log par défaut utiliser java.util.logging.Logger
  • LogCat utilise loggeravec nom "", pour en obtenir une instance, utilisezLogManager.getLogManager().getLogger("")
  • Les appareils Android s'ajoutent à l' loggerinstance LogCat com.android.internal.logging.AndroidHandleraprès l'exécution des applications de débogage
  • Mais!!! com.android.internal.logging.AndroidHandlerimprime les messages dans logcat uniquement avec des niveaux supérieurs à java.util.logging.Level.INFOceux de ( Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF)

Donc, pour écrire des journaux dans un fichier, il suffit d' rootLogger "" ajouter un 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
        }
    }
}

Pour imprimer tous les enregistreurs de votre application, utilisez:

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
la source
Salut. Quel est l'avantage d'utiliser cet "" enregistreur. Je ne vois aucune différence avec un enregistreur personnalisé. ou est-ce que je manque quelque chose?
Abins Shaji
1

Cette variante est beaucoup plus courte

essayez {
    chemin du fichier final = nouveau fichier (
            Environment.getExternalStorageDirectory (), "DBO_logs5");
    if (! chemin.exists ()) {
        path.mkdir ();
    }
    Runtime.getRuntime (). Exec (
            "logcat -d -f" + chemin + File.separator
                    + "dbo_logcat"
                    + ".txt");
} catch (IOException e) {
    e.printStackTrace ();
}
xoxol_89
la source
1

Vous pouvez utiliser la bibliothèque que j'ai écrite. C'est très simple à utiliser:

Ajoutez cette dépendance à votre fichier gradle:

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

Initialisez la bibliothèque dans la classe 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
    }

Voici comment vous utilisez la bibliothèque:

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

Et voici comment récupérer les journaux:

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

Voici le lien vers la page github avec plus d'informations: https://github.com/danylovolokh/AndroidLogger

J'espère que ça aide.

Danylo Volokh
la source
1

La plupart des versions précédentes de log4j ne fonctionnent pas maintenant (05/2019). Mais vous pouvez utiliser Hyperlog - je peux confirmer que cela fonctionne.

  1. Ajoutez cette ligne à vos dépendances et à votre projet de synchronisation

    implementation 'com.hypertrack:hyperlog:0.0.10'
  2. Créez une nouvelle classe d'application (créez une nouvelle classe java et étendez l'application). Ensuite, dans la méthode onCreate, ajoutez ces lignes:

    HyperLog.initialize(this);
    HyperLog.setLogLevel(Log.VERBOSE);
    
    HyperLog.getDeviceLogsInFile(this);
  3. Modifiez le fichier manifeste pour définir le fichier d'application.

    <application
        android:name=".AppClass"
        .....
  4. Différentes façons de se connecter:

    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. Trouvez vos fichiers journaux. Aller vers

    RootFolder/android/data/"appPackageName/LogFiles/
Haider Malik
la source
J'ai essayé cette bibliothèque, dans le fichier généré avec HyperLog.getDeviceLogsInFile (this); seul le dernier journal généré est là
mad_greasemonkey