Tous les produits
Search
Centre de documentation

ApsaraVideo VOD:Système de journalisation

Dernière mise à jour :Sep 09, 2026

Cette rubrique présente les concepts fondamentaux, les fonctionnalités et l'utilisation du système de journalisation d'AliPlayerKit, LogHub.

Concepts

Qu'est-ce que LogHub ?

LogHub est le point d'entrée unifié pour toutes les sorties de journal dans le framework PlayerKit. Il s'agit d'une classe utilitaire statique qui offre des fonctionnalités de journalisation cohérentes.

LogHub encapsule l'API native Log d'Android. Il conserve toutes les capacités d'origine et ajoute les fonctionnalités principales suivantes :

Fonctionnalités

Description

Activation/désactivation des journaux

Contrôle la sortie ou non des journaux.

Activation/désactivation de la console

Contrôle la sortie ou non des journaux vers Logcat.

Filtrage par niveau

Affiche uniquement les journaux au niveau spécifié ou supérieur.

Mécanisme d'écouteurs

Prend en charge des écouteurs externes pour une gestion personnalisée des journaux, comme l'écriture dans des fichiers.

Qu'est-ce qu'un écouteur de journal ?

LogHubListener est une interface de rappel qui reçoit les journaux de LogHub. Implémentez cette interface pour personnaliser la manière dont les journaux sont traités. Par exemple :

  • Écrivez les journaux dans un fichier afin de les partager avec le support technique lors du dépannage.

  • Téléchargez les journaux sur un serveur distant pour une collecte centralisée.

  • Affichez les journaux dans l'interface utilisateur pour un panneau de débogage.

Fonctionnalités

Problèmes résolus

  • Les journaux sont dispersés dans le code, ce qui rend leur gestion et leur filtrage difficiles.

  • Les versions de production doivent désactiver les journaux de débogage, mais aucun commutateur unifié n'existe.

  • Aucune prise en charge intégrée des fichiers journaux pour le dépannage.

  • Les journaux du SDK Player et les journaux métier sont séparés, ce qui rend l'analyse associative difficile.

Valeur principale

Utilisation

Description

Avantage

Utilisation de base

Utilisez LogHub directement pour afficher les journaux.

Aucune configuration requise. Fonctionne immédiatement.

Contrôle des niveaux

Définissez le filtrage des niveaux de journal.

Journaux détaillés pour le développement. Journaux minimaux pour la production.

Extension via écouteur

Enregistrez un écouteur pour gérer les journaux.

Permet la persistance des journaux et le reporting à distance.

Avantages architecturaux :

  • Point d'entrée unifié : Tous les journaux transitent par LogHub, ce qui simplifie la gestion et le contrôle.

  • Contrôle flexible : Prend en charge trois niveaux de contrôle : activation globale, activation de la console et filtrage par niveau.

  • Extensible : Le mécanisme d'écouteurs prend en charge la gestion personnalisée des journaux, telle que l'écriture dans des fichiers et le reporting à distance.

  • Sécurité des threads : La liste des écouteurs utilise CopyOnWriteArrayList pour un accès concurrent sécurisé.

Capacités principales

Capacité

Description

Journalisation multiniveau

Prend en charge les niveaux VERBOSE, DEBUG, INFO, WARN et ERROR.

Journalisation des exceptions

Prend en charge l'affichage des détails des exceptions Throwable.

Segmentation des longs journaux

Segment automatiquement les longs journaux pour éviter la troncature par Logcat.

Journalisation des performances

Fournit des journaux de chronométrage des performances pour l'analyse.

Intégration des journaux du SDK

Gère uniformément les journaux du SDK Player via l'interface IPlayerLogger.

Composants intégrés

Niveaux de journal

Niveau

Valeur

Description

Scénario

VERBOSE

0

Niveau le plus détaillé. Affiche toutes les informations de débogage.

Développement et débogage.

DEBUG

1

Niveau d'information de débogage.

Débogage de fonctionnalités spécifiques.

INFO

2

Niveau d'information. Affiche les messages généraux.

Niveau par défaut. Recommandé pour la production.

WARN

3

Niveau d'avertissement. Indique des problèmes potentiels.

Surveillance des risques potentiels.

ERROR

4

Niveau d'erreur. Signale les erreurs.

Surveillance des problèmes critiques.

NONE

100

Désactive tous les journaux.

Désactive la sortie des journaux.

Classes principales

Classe

Description

LogHub

Classe utilitaire pour le centre de journaux. Point d'entrée unifié pour la sortie des journaux.

LogLevel

Annotation qui définit les niveaux de journal.

LogInfo

Classe de données qui encapsule les informations complètes d'une entrée de journal unique.

LogHubListener

Interface de rappel pour recevoir les rappels de journal.

IPlayerLogger

Interface globale de journalisation du lecteur qui encapsule la fonctionnalité de journalisation du SDK.

DefaultPlayerLogger

Implémentation par défaut du journaliseur du lecteur.

LoggerCallback

Interface de rappel pour les journaux du lecteur.

Utilisation de base

Le système de journalisation propose trois stratégies d'utilisation. Choisissez celle qui correspond à vos besoins.

Stratégie

Description

Scénario

Sortie directe des journaux

Méthode la plus simple. Appelez directement les méthodes LogHub.

Développement, débogage ou journalisation temporaire.

Configuration du niveau de journal

Définissez différents niveaux de journal en fonction de l'environnement.

Distinguer les environnements de développement et de production.

Enregistrement d'un écouteur

Personnalisez la gestion des journaux à l'aide d'un écouteur.

Persistance des journaux ou reporting à distance.

Stratégie 1 : Sortie directe des journaux

Appelez directement les méthodes statiques de LogHub :

// Output an INFO log
LogHub.i(this, "playVideo", "Start playing video");

// Output a WARN log
LogHub.w(this, "onBuffering", "Buffering. Current progress: ", progress);

// Output an ERROR log
LogHub.e(this, "onError", "Playback failed. Error code: ", errorCode);

// Output an ERROR log with an exception
LogHub.e(this, "onException", throwable, "An exception occurred");

// Output a performance timing log
LogHub.t("loadVideoSource", costTime);

Format du journal :

[Class name] Method name: Message

Suggestion de filtrage Logcat :

package:mine tag:AliPlayerKit

Stratégie 2 : Configuration du niveau de journal

Définissez différents niveaux de journal en fonction de l'environnement d'exécution :

// Development environment: Output all logs
if (BuildConfig.DEBUG) {
    LogHub.setEnableLog(true);
    LogHub.setEnableConsoleLog(true);
    LogHub.setLogLevel(LogLevel.VERBOSE);
}

// Production environment: Output only INFO and above
else {
    LogHub.setEnableLog(true);
    LogHub.setEnableConsoleLog(false);  // Disable console output
    LogHub.setLogLevel(LogLevel.INFO);
}

// Disable all logs (for sensitive scenarios)
LogHub.setEnableLog(false);

Stratégie 3 : Enregistrement d'un écouteur

Personnalisez la gestion des journaux à l'aide d'un écouteur :

// Create a listener
LogHubListener listener = logInfo -> {
    // Process the log
    String formattedLog = logInfo.getFormattedMessage();
    // Write to file, upload to server, etc.
    saveToFile(formattedLog);
};

// Register the listener
LogHub.addListener(listener);

// Remove the listener when no longer needed
LogHub.removeListener(listener);   

Utilisation avancée

Comment implémenter la persistance des journaux ?

Implémentez la journalisation basée sur des fichiers à l'aide de l'interface LogHubListener pour faciliter le dépannage.

  1. Créez un écouteur de journal.

    public class FileLogListener implements LogHubListener {
    
        private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
        private final File mLogFile;
    
        public FileLogListener(Context context) {
            // Log file path
            File logDir = new File(context.getExternalFilesDir(null), "logs");
            if (!logDir.exists()) {
                logDir.mkdirs();
            }
            mLogFile = new File(logDir, "player_" + getDateStr() + ".log");
        }
    
        @Overridepublic void onLog(@NonNull LogInfo logInfo) {
            // Write to file asynchronously to avoid blocking the calling thread
            mExecutor.execute(() -> {
                try {
                    String log = logInfo.getFormattedMessage() + "\n";
                    FileOutputStream fos = new FileOutputStream(mLogFile, true);
                    fos.write(log.getBytes(StandardCharsets.UTF_8));
                    fos.close();
                } catch (IOException e) {
                    // Ignore write exceptions
                }
            });
        }
    }
  2. Enregistrez-le dans votre classe Application.

    public class MyApplication extends Application {
    
        private FileLogListener mFileLogListener;
    
        @Overridepublic void onCreate() {
            super.onCreate();
    
            // Create and register the file log listener
            mFileLogListener = new FileLogListener(this);
            LogHub.addListener(mFileLogListener);
        }
    }
  3. Récupérez le fichier journal.

    // Log file path
    File logDir = new File(getExternalFilesDir(null), "logs");
    File[] logFiles = logDir.listFiles();
    
    // Share with technical support for analysis

Exemple de référence : playerkit-examples/example-log-system/FileLogListener.java.

Comment intégrer les journaux du SDK Player ?

Utilisez l'interface IPlayerLogger pour gérer uniformément les journaux du SDK Player.

  1. Créez une instance de journaliseur du lecteur.

    // Initialize in Application
    IPlayerLogger playerLogger = new DefaultPlayerLogger(context);
    
    // Enable SDK console logs (enable only for debugging)
    playerLogger.enableConsoleLog(BuildConfig.DEBUG);
    
    // Set SDK log level
    playerLogger.setLogLevel(LogLevel.INFO);
  2. Définissez le rappel de journal du SDK.

    playerLogger.setLogCallback((level, message) -> {
        // Handle SDK logs, such as writing to file or reporting remotely
        LogHub.log(level, "PlayerSDK", message);
    });

Comment afficher les journaux dans l'interface utilisateur ?

Utilisez un écouteur pour afficher les journaux en temps réel à l'écran.

public class LogPanelActivity extends AppCompatActivity {

    private TextView mTvLogOutput;
    private LogHubListener mLogListener;

    @Overrideprotected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_log_panel);

        mTvLogOutput = findViewById(R.id.tv_log_output);

        // Create a UI log listener
        mLogListener = logInfo -> runOnUiThread(() -> {
            mTvLogOutput.append(logInfo.getFormattedMessage() + "\n");
        });

        // Register the listener
        LogHub.addListener(mLogListener);
    }

    @Overrideprotected void onDestroy() {
        super.onDestroy();
        // Remove the listener to prevent memory leaks
        LogHub.removeListener(mLogListener);
    }
}

Bonnes pratiques

Sélection des niveaux de journal

Scénario

Niveau recommandé

Description

Informations de débogage détaillées

VERBOSE

Suivre les flux de travail pendant le développement.

Points de débogage clés

DEBUG

Enregistrer les changements d'état clés.

Informations métier importantes

INFO

Conserver les informations importantes en production.

Avertissements de problèmes potentiels

WARN

Exceptions récupérables ou avertissements de performance.

Erreurs critiques

ERROR

Erreurs provoquant l'échec des fonctionnalités.

Configuration de l'environnement de production

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        if (BuildConfig.DEBUG) {
            // Development: Detailed logs + console output
            LogHub.setEnableLog(true);
            LogHub.setEnableConsoleLog(true);
            LogHub.setLogLevel(LogLevel.VERBOSE);
        } else {
            // Production: Minimal logs + no console + file persistence
            LogHub.setEnableLog(true);
            LogHub.setEnableConsoleLog(false);  // Disable Logcat output
            LogHub.setLogLevel(LogLevel.INFO);   // Keep only INFO and above
            LogHub.addListener(new FileLogListener(this));
        }
    }
}  

Remarques

Remarque

Description

Éviter les informations sensibles

Ne journalisez pas la confidentialité des utilisateurs, les clés ou d'autres informations sensibles.

Écriture asynchrone dans les fichiers

Écrivez dans les fichiers de manière asynchrone dans les écouteurs pour éviter les blocages.

Gérer les exceptions des écouteurs

Les exceptions des écouteurs ne doivent pas affecter la sortie normale des journaux.

Supprimer rapidement les écouteurs

Supprimez les écouteurs lorsque les pages sont détruites pour éviter les fuites de mémoire.

Emplacement de l'écouteur global

Placez les écouteurs de journaux de fichiers dans la classe Application pour garantir une collecte sur tout le cycle de vie.

Exemples

Le projet inclut un exemple complet à l'emplacement playerkit-examples/example-log-system.

Fonctionnalités de l'exemple

Fonctionnalité

Description

Démonstration de sortie de journal

Montre la sortie de journal à chaque niveau.

Affichage des journaux dans l'interface utilisateur

Affiche les journaux en temps réel à l'écran.

Écouteur de journal de fichier

Montre la persistance des journaux.

Exécution de l'exemple

Dans l'application Demo, sélectionnez l'exemple Log System pour voir les résultats.

Référence API

Interfaces principales

Interface/classe

Description

LogHub

Centre de journaux. Point d'entrée unifié pour la sortie des journaux.

LogHubListener

Interface de rappel pour recevoir les rappels de journal.

LogInfo

Classe de données pour les informations de journal.

IPlayerLogger

Interface globale de journalisation du lecteur.

Méthodes principales de LogHub

Méthode

Description

setEnableLog(boolean)

Active ou désactive la sortie des journaux (commutateur global).

setEnableConsoleLog(boolean)

Active ou désactive la sortie des journaux de la console.

setLogLevel(int)

Définit le filtrage des niveaux de journal.

addListener(LogHubListener)

Ajoute un écouteur de journal.

removeListener(LogHubListener)

Supprime un écouteur de journal.

v/d/i/w/e(Object, String, Object...)

Affiche les journaux à chaque niveau.

t(String, long)

Affiche les journaux de chronométrage des performances.

Méthodes principales de LogInfo

Méthode

Description

getLevel()

Obtient le niveau de journal.

getTag()

Obtient la balise du journal.

getMessage()

Obtient le message du journal.

getThrowable()

Obtient les informations sur l'exception.

getThreadName()

Obtient le nom du thread.

getTimestamp()

Obtient l'horodatage (en millisecondes).

getFormattedMessage()

Obtient la chaîne de journal formatée.

Principes techniques

Segmentation des longs journaux

Logcat limite chaque ligne de journal à environ 4000 caractères. LogHub gère les longs journaux en les segmentant :

private static final int BUFFER_SIZE = 3000;

// Segment and output to Logcatwhile (startIndex < length) {
    int endIndex = Math.min(length, startIndex + BUFFER_SIZE);
    String sub = s.substring(startIndex, endIndex);
    // Output segmented log...
    startIndex = endIndex;
}

Optimisation : Envoyez les journaux complets aux écouteurs. Segmentez uniquement pour la sortie Logcat.

Sécurité des threads

La liste des écouteurs utilise CopyOnWriteArrayList pour garantir la sécurité des threads :

private static final List<LogHubListener> sListeners = new CopyOnWriteArrayList<>();

Caractéristiques :

  • Les opérations de lecture ne nécessitent aucun verrou. Les performances sont élevées.

  • Les opérations d'écriture copient un nouveau tableau. Les lectures en cours ne sont pas affectées.

  • Idéal pour l'enregistrement et la suppression d'écouteurs, où les lectures sont beaucoup plus nombreuses que les écritures.

FAQ

Comment filtrer les journaux PlayerKit dans Logcat ?

Utilisez ce filtre :

package:mine tag:AliPlayerKit

Ou filtrez par niveau :

package:mine tag:AliPlayerKit level:info       

Où sont stockés les fichiers journaux de l'environnement de production ?

Chemin par défaut (si vous utilisez l'exemple FileLogListener) :

/sdcard/Android/data/[package name]/files/logs/

Sur quel thread s'exécutent les rappels des écouteurs ?

Les rappels des écouteurs s'exécutent sur le même thread que celui qui émet le journal. Pour traiter les journaux sur le thread d'interface utilisateur, utilisez runOnUiThread() pour changer de thread.

Erreurs courantes

Voici les problèmes les plus fréquemment signalés par les clients. Évitez-les :

Erreur 1 : Les opérations de blocage dans les écouteurs provoquent des ralentissements

Code incorrect :

@Overridepublic void onLog(@NonNull LogInfo logInfo) {
    // Synchronous file write on main thread blocks the UItry {
        FileOutputStream fos = new FileOutputStream(mLogFile, true);
        fos.write(logInfo.getFormattedMessage().getBytes());
        fos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Code correct :

private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();

@Overridepublic void onLog(@NonNull LogInfo logInfo) {
    // Write to file asynchronously
    mExecutor.execute(() -> {
        try {
            // File write logic...
        } catch (IOException e) {
            // Ignore
        }
    });
}

Cause racine : Si les journaux sont émis sur le thread principal, les écritures synchrones dans les fichiers bloquent l'interface utilisateur. Cela provoque des ralentissements ou des ANR (Application Not Responding).

Erreur 2 : Oublier de supprimer les écouteurs provoque des fuites de mémoire

Code incorrect :

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Registered a listener but never removed it
    LogHub.addListener(logInfo -> {
        mTvLogOutput.append(logInfo.getMessage());
    });
}

Code correct :

private LogHubListener mLogListener;

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mLogListener = logInfo -> runOnUiThread(() -> {
        mTvLogOutput.append(logInfo.getMessage());
    });
    LogHub.addListener(mLogListener);
}

@Overrideprotected void onDestroy() {
    super.onDestroy();
    // Remove the listener promptlyif (mLogListener != null) {
        LogHub.removeListener(mLogListener);
    }
}

Cause racine : L'écouteur détient une référence à l'Activity. Si l'Activity est détruite mais que l'écouteur reste, l'Activity ne peut pas être récupérée par le garbage collector. Cela provoque une fuite de mémoire.

Erreur 3 : Les exceptions des écouteurs affectent les autres écouteurs

Code incorrect :

@Overridepublic void onLog(@NonNull LogInfo logInfo) {
    // Unhandled exception. If thrown here, it affects other listeners
    String data = logInfo.getMessage();
    int result = 1 / 0;  // Throws exception
}

Code correct :

@Overridepublic void onLog(@NonNull LogInfo logInfo) {
    try {
        // Handle exceptions inside the listener
        processLog(logInfo);
    } catch (Exception e) {
        // Handle listener-specific exceptions without affecting the logging system
        android.util.Log.e("FileLogListener", "Error processing log", e);
    }
}

Cause racine : Bien que LogHub intercepte les exceptions des écouteurs en interne, les écouteurs doivent gérer leurs propres exceptions pour garantir la stabilité.

Comment déboguer ?

  1. Vérifiez l'état d'activation des journaux :

    boolean enabled = LogHub.isLogEnabled();
    boolean consoleEnabled = LogHub.isConsoleLogEnabled();
    int level = LogHub.getLogLevel();
  2. Consultez la sortie Logcat :

    Filtrez les journaux à l'aide de tag:AliPlayerKit.

  3. Vérifiez le nombre d'écouteurs :

    Vous pouvez inspecter le nombre d'écouteurs enregistrés à l'aide de la réflexion (uniquement pour le débogage). Vérifiez que les écouteurs sont correctement enregistrés et supprimés.