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 |
|
|
Classe utilitaire pour le centre de journaux. Point d'entrée unifié pour la sortie des journaux. |
|
|
Annotation qui définit les niveaux de journal. |
|
|
Classe de données qui encapsule les informations complètes d'une entrée de journal unique. |
|
|
Interface de rappel pour recevoir les rappels de journal. |
|
|
Interface globale de journalisation du lecteur qui encapsule la fonctionnalité de journalisation du SDK. |
|
|
Implémentation par défaut du journaliseur du lecteur. |
|
|
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.
-
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 } }); } } -
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); } } -
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.
-
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); -
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 |
|
|
Centre de journaux. Point d'entrée unifié pour la sortie des journaux. |
|
|
Interface de rappel pour recevoir les rappels de journal. |
|
|
Classe de données pour les informations de journal. |
|
|
Interface globale de journalisation du lecteur. |
Méthodes principales de LogHub
|
Méthode |
Description |
|
|
Active ou désactive la sortie des journaux (commutateur global). |
|
|
Active ou désactive la sortie des journaux de la console. |
|
|
Définit le filtrage des niveaux de journal. |
|
|
Ajoute un écouteur de journal. |
|
|
Supprime un écouteur de journal. |
|
|
Affiche les journaux à chaque niveau. |
|
|
Affiche les journaux de chronométrage des performances. |
Méthodes principales de LogInfo
|
Méthode |
Description |
|
|
Obtient le niveau de journal. |
|
|
Obtient la balise du journal. |
|
|
Obtient le message du journal. |
|
|
Obtient les informations sur l'exception. |
|
|
Obtient le nom du thread. |
|
|
Obtient l'horodatage (en millisecondes). |
|
|
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 ?
-
Vérifiez l'état d'activation des journaux :
boolean enabled = LogHub.isLogEnabled(); boolean consoleEnabled = LogHub.isConsoleLogEnabled(); int level = LogHub.getLogLevel(); -
Consultez la sortie Logcat :
Filtrez les journaux à l'aide de
tag:AliPlayerKit. -
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.