Topik ini memperkenalkan konsep inti, fitur, dan penggunaan sistem logging AliPlayerKit, yaitu LogHub.
Konsep
Apa itu LogHub?
LogHub adalah titik masuk terpadu untuk seluruh output log dalam framework PlayerKit. Ini merupakan kelas utilitas statis yang menyediakan fungsionalitas logging yang konsisten.
LogHub membungkus API Log native Android, mempertahankan semua kemampuan aslinya sekaligus menambahkan fitur inti berikut:
Kemampuan | Deskripsi |
Log toggle | Mengontrol apakah log di-output atau tidak. |
Console toggle | Mengontrol apakah log di-output ke Logcat. |
Level filtering | Hanya meng-output log pada level yang ditentukan atau lebih tinggi. |
Listener mechanism | Mendukung pendengar eksternal untuk penanganan log kustom, seperti menulis ke file. |
Apa itu log listener?
LogHubListener adalah antarmuka callback yang menerima log dari LogHub. Implementasikan antarmuka ini untuk menyesuaikan cara penanganan log, misalnya:
Menulis log ke file untuk dibagikan kepada dukungan teknis saat troubleshooting.
Mengunggah log ke server jarak jauh untuk pengumpulan terpusat.
Menampilkan log di UI untuk panel debugging.
Fitur
Masalah yang diselesaikan
Log tersebar di seluruh basis kode, sehingga sulit dikelola dan difilter.
Build rilis perlu menonaktifkan log debug, tetapi tidak tersedia toggle terpadu.
Tidak ada dukungan log file bawaan untuk troubleshooting.
Log SDK player dan log bisnis terpisah, sehingga analisis asosiasi menjadi sulit.
Nilai inti
Penggunaan | Deskripsi | Keuntungan |
Basic usage | Gunakan LogHub secara langsung untuk meng-output log. | Tidak perlu konfigurasi. Berfungsi langsung tanpa pengaturan tambahan. |
Level control | Atur filter level log. | Log detail untuk pengembangan. Log minimal untuk produksi. |
Listener extension | Daftarkan pendengar untuk menangani log. | Memungkinkan persistensi log dan pelaporan jarak jauh. |
Keunggulan arsitektural:
Unified entry: Semua log mengalir melalui LogHub, menyederhanakan manajemen dan kontrol.
Flexible control: Mendukung tiga lapisan kontrol: toggle global, toggle konsol, dan filter level.
Extensible: Mekanisme pendengar mendukung penanganan log kustom, seperti penulisan ke file dan pelaporan jarak jauh.
Thread safe: Daftar pendengar menggunakan CopyOnWriteArrayList untuk akses konkuren yang aman.
Kemampuan inti
Kemampuan | Deskripsi |
Multi-level logging | Mendukung level VERBOSE, DEBUG, INFO, WARN, dan ERROR. |
Exception logging | Mendukung output detail exception Throwable. |
Long-log segmentation | Secara otomatis membagi log panjang untuk menghindari pemotongan oleh Logcat. |
Performance logging | Menyediakan log timing performa untuk analisis. |
SDK log integration | Mengelola log SDK player secara terpadu melalui antarmuka IPlayerLogger. |
Komponen bawaan
Level log
Level | Nilai | Deskripsi | Skenario |
VERBOSE | 0 | Level paling detail. Meng-output semua informasi debug. | Pengembangan dan debugging. |
DEBUG | 1 | Level informasi debug. | Debugging fitur tertentu. |
INFO | 2 | Level informasi. Meng-output pesan umum. | Level default. Direkomendasikan untuk produksi. |
WARN | 3 | Level peringatan. Menunjukkan potensi masalah. | Memantau risiko potensial. |
ERROR | 4 | Level error. Melaporkan kesalahan. | Memantau masalah kritis. |
NONE | 100 | Menonaktifkan semua log. | Mematikan output log. |
Kelas inti
Kelas | Deskripsi |
| Kelas utilitas untuk pusat log. Titik masuk terpadu untuk output log. |
| Anotasi yang mendefinisikan level log. |
| Kelas data yang mengenkapsulasi informasi lengkap untuk satu entri log. |
| Antarmuka callback untuk menerima callback log. |
| Antarmuka logging player global yang mengenkapsulasi fungsionalitas logging SDK. |
| Implementasi default logger player. |
| Antarmuka callback untuk log player. |
Penggunaan dasar
Sistem logging menyediakan tiga strategi penggunaan. Pilih yang sesuai dengan kebutuhan Anda.
Strategi | Deskripsi | Skenario |
Direct log output | Metode paling sederhana. Panggil metode LogHub secara langsung. | Pengembangan, debugging, atau logging sementara. |
Configure log level | Atur level log berbeda berdasarkan lingkungan. | Membedakan antara lingkungan pengembangan dan produksi. |
Register a listener | Menyesuaikan penanganan log menggunakan pendengar. | Persistensi log atau pelaporan jarak jauh. |
Strategi 1: Direct log output
Anda dapat memanggil metode statis LogHub secara langsung:
// Output log INFO
LogHub.i(this, "playVideo", "Mulai memutar video");
// Output log WARN
LogHub.w(this, "onBuffering", "Buffering. Progres saat ini: ", progress);
// Output log ERROR
LogHub.e(this, "onError", "Pemutaran gagal. Kode error: ", errorCode);
// Output log ERROR dengan exception
LogHub.e(this, "onException", throwable, "Terjadi exception");
// Output log timing performa
LogHub.t("loadVideoSource", costTime);Format log:
[Nama kelas] Nama metode: PesanSaran filter Logcat:
package:mine tag:AliPlayerKitStrategi 2: Configure log level
Anda dapat mengatur level log berbeda berdasarkan lingkungan runtime:
// Lingkungan pengembangan: Output semua log
if (BuildConfig.DEBUG) {
LogHub.setEnableLog(true);
LogHub.setEnableConsoleLog(true);
LogHub.setLogLevel(LogLevel.VERBOSE);
}
// Lingkungan produksi: Hanya output INFO dan di atasnya
else {
LogHub.setEnableLog(true);
LogHub.setEnableConsoleLog(false); // Nonaktifkan output konsol
LogHub.setLogLevel(LogLevel.INFO);
}
// Nonaktifkan semua log (untuk skenario sensitif)
LogHub.setEnableLog(false);Strategi 3: Register a listener
Anda dapat menyesuaikan penanganan log menggunakan pendengar:
// Buat pendengar
LogHubListener listener = logInfo -> {
// Proses log
String formattedLog = logInfo.getFormattedMessage();
// Tulis ke file, unggah ke server, dll.
saveToFile(formattedLog);
};
// Daftarkan pendengar
LogHub.addListener(listener);
// Hapus pendengar jika tidak lagi diperlukan
LogHub.removeListener(listener); Penggunaan lanjutan
Bagaimana cara mengimplementasikan persistensi log?
Implementasikan logging berbasis file menggunakan antarmuka LogHubListener untuk membantu troubleshooting.
Buat pendengar log.
public class FileLogListener implements LogHubListener { private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); private final File mLogFile; public FileLogListener(Context context) { // Jalur file log 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) { // Tulis ke file secara asinkron untuk menghindari pemblokiran thread pemanggil 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) { // Abaikan exception penulisan } }); } }Daftarkan di kelas Application Anda.
public class MyApplication extends Application { private FileLogListener mFileLogListener; @Overridepublic void onCreate() { super.onCreate(); // Buat dan daftarkan pendengar log file mFileLogListener = new FileLogListener(this); LogHub.addListener(mFileLogListener); } }Ambil file log.
// Jalur file log File logDir = new File(getExternalFilesDir(null), "logs"); File[] logFiles = logDir.listFiles(); // Bagikan kepada dukungan teknis untuk analisis
Referensi contoh: playerkit-examples/example-log-system/FileLogListener.java.
Bagaimana cara mengintegrasikan log SDK player?
Gunakan antarmuka IPlayerLogger untuk mengelola log SDK player secara terpadu.
Buat instans logger player.
// Inisialisasi di Application IPlayerLogger playerLogger = new DefaultPlayerLogger(context); // Aktifkan log konsol SDK (aktifkan hanya untuk debugging) playerLogger.enableConsoleLog(BuildConfig.DEBUG); // Atur level log SDK playerLogger.setLogLevel(LogLevel.INFO);Atur callback log SDK.
playerLogger.setLogCallback((level, message) -> { // Tangani log SDK, seperti menulis ke file atau melaporkan jarak jauh LogHub.log(level, "PlayerSDK", message); });
Bagaimana cara menampilkan log di UI?
Anda dapat menggunakan pendengar untuk menampilkan log secara real-time di layar.
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);
// Buat pendengar log UI
mLogListener = logInfo -> runOnUiThread(() -> {
mTvLogOutput.append(logInfo.getFormattedMessage() + "\n");
});
// Daftarkan pendengar
LogHub.addListener(mLogListener);
}
@Overrideprotected void onDestroy() {
super.onDestroy();
// Hapus pendengar untuk mencegah memory leak
LogHub.removeListener(mLogListener);
}
}Praktik terbaik
Pemilihan level log
Skenario | Level yang direkomendasikan | Deskripsi |
Detailed debug information | VERBOSE | Jejak alur kerja selama pengembangan. |
Debug key points | DEBUG | Catat perubahan status kunci. |
Important business information | INFO | Pertahankan informasi penting di produksi. |
Potential issue warnings | WARN | Exception yang dapat dipulihkan atau peringatan performa. |
Critical errors | ERROR | Kesalahan yang menyebabkan kegagalan fitur. |
Konfigurasi lingkungan produksi
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
// Pengembangan: Log detail + output konsol
LogHub.setEnableLog(true);
LogHub.setEnableConsoleLog(true);
LogHub.setLogLevel(LogLevel.VERBOSE);
} else {
// Produksi: Log minimal + tanpa konsol + persistensi file
LogHub.setEnableLog(true);
LogHub.setEnableConsoleLog(false); // Nonaktifkan output Logcat
LogHub.setLogLevel(LogLevel.INFO); // Pertahankan hanya INFO dan di atasnya
LogHub.addListener(new FileLogListener(this));
}
}
} Catatan
Catatan | Deskripsi |
Avoid sensitive information | Jangan mencatat privasi pengguna, kunci, atau informasi sensitif lainnya. |
Asynchronous file writes | Tulis file secara asinkron di pendengar untuk menghindari pemblokiran. |
Handle listener exceptions | Exception pada pendengar tidak boleh memengaruhi output log normal. |
Remove listeners promptly | Hapus pendengar saat halaman dihancurkan untuk mencegah memory leak. |
Global listener location | Tempatkan pendengar log file di kelas Application untuk memastikan pengumpulan sepanjang siklus hidup. |
Contoh
Proyek menyertakan contoh lengkap di playerkit-examples/example-log-system.
Fitur contoh
Fitur | Deskripsi |
Log output demo | Menunjukkan output log pada setiap level. |
UI log display | Menampilkan log secara real-time di layar. |
File log listener | Menunjukkan persistensi log. |
Menjalankan Contoh
Di Aplikasi Demo, pilih contoh Log System untuk melihat hasilnya.
Referensi API
Antarmuka inti
Antarmuka/kelas | Deskripsi |
| Pusat log. Titik masuk terpadu untuk output log. |
| Antarmuka callback untuk menerima callback log. |
| Kelas data untuk informasi log. |
| Antarmuka logging player global. |
Metode utama LogHub
Metode | Deskripsi |
| Aktifkan atau nonaktifkan output log (toggle global). |
| Aktifkan atau nonaktifkan output log konsol. |
| Atur filter level log. |
| Tambahkan pendengar log. |
| Hapus pendengar log. |
| Output log pada setiap level. |
| Output log timing performa. |
Metode utama LogInfo
Metode | Deskripsi |
| Dapatkan level log. |
| Dapatkan tag log. |
| Dapatkan pesan log. |
| Dapatkan informasi exception. |
| Dapatkan nama thread. |
| Dapatkan timestamp (dalam milidetik). |
| Dapatkan string log yang telah diformat. |
Prinsip teknis
Long-log segmentation
Logcat membatasi setiap baris log hingga sekitar 4000 karakter. LogHub menangani log panjang dengan membaginya:
private static final int BUFFER_SIZE = 3000;
// Bagi dan output ke Logcatwhile (startIndex < length) {
int endIndex = Math.min(length, startIndex + BUFFER_SIZE);
String sub = s.substring(startIndex, endIndex);
// Output log tersegmentasi...
startIndex = endIndex;
}Optimasi: Kirim log lengkap ke pendengar. Hanya segmentasi untuk output Logcat.
Thread safety
Daftar pendengar menggunakan CopyOnWriteArrayList untuk memastikan keamanan thread:
private static final List<LogHubListener> sListeners = new CopyOnWriteArrayList<>();Karakteristik:
Operasi baca tidak memerlukan lock. Performa tinggi.
Operasi tulis menyalin array baru. Pembacaan yang sedang berlangsung tidak terpengaruh.
Ideal untuk pendaftaran dan penghapusan pendengar, di mana operasi baca jauh lebih sering daripada tulis.
FAQ
Bagaimana cara memfilter log PlayerKit di Logcat?
Gunakan filter ini:
package:mine tag:AliPlayerKitAtau filter berdasarkan level:
package:mine tag:AliPlayerKit level:info Di mana file log lingkungan produksi disimpan?
Jalur default (jika menggunakan contoh FileLogListener):
/sdcard/Android/data/[nama paket]/files/logs/Thread mana yang menjalankan callback pendengar?
Callback pendengar dijalankan pada thread yang sama dengan tempat log di-output. Untuk memproses log di thread UI, gunakan runOnUiThread() untuk mengganti thread.
Kesalahan umum
Berikut adalah masalah paling sering dilaporkan pelanggan. Hindari hal-hal ini:
Kesalahan 1: Operasi pemblokiran di pendengar menyebabkan tersendat
Kode salah:
@Overridepublic void onLog(@NonNull LogInfo logInfo) {
// Penulisan file sinkron di main thread memblokir UItry {
FileOutputStream fos = new FileOutputStream(mLogFile, true);
fos.write(logInfo.getFormattedMessage().getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Kode yang benar:
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@Overridepublic void onLog(@NonNull LogInfo logInfo) {
// Tulis ke file secara asinkron
mExecutor.execute(() -> {
try {
// Logika penulisan file...
} catch (IOException e) {
// Abaikan
}
});
}
Akar penyebab: Jika log di-output di main thread, penulisan file sinkron akan memblokir UI. Hal ini menyebabkan tersendat atau ANR.
Kesalahan 2: Lupa menghapus pendengar menyebabkan memory leak
Kode salah:
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Mendaftarkan pendengar tetapi tidak pernah menghapusnya
LogHub.addListener(logInfo -> {
mTvLogOutput.append(logInfo.getMessage());
});
}
Kode yang benar:
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();
// Hapus pendengar segeraif (mLogListener != null) {
LogHub.removeListener(mLogListener);
}
}
Akar penyebab: Pendengar menyimpan referensi ke Activity. Jika Activity dihancurkan tetapi pendengar tetap ada, Activity tidak dapat dikumpulkan oleh garbage collector. Hal ini menyebabkan memory leak.
Kesalahan 3: Exception pada pendengar memengaruhi pendengar lain
Kode salah:
@Overridepublic void onLog(@NonNull LogInfo logInfo) {
// Exception tidak ditangani. Jika dilempar di sini, akan memengaruhi pendengar lain
String data = logInfo.getMessage();
int result = 1 / 0; // Melempar exception
}
Kode benar:
@Overridepublic void onLog(@NonNull LogInfo logInfo) {
try {
// Tangani exception di dalam pendengar
processLog(logInfo);
} catch (Exception e) {
// Tangani exception spesifik pendengar tanpa memengaruhi sistem logging
android.util.Log.e("FileLogListener", "Error processing log", e);
}
}Akar penyebab: Meskipun LogHub menangkap exception pendengar secara internal, pendengar harus menangani exception-nya sendiri untuk menjamin stabilitas.
Bagaimana cara melakukan debugging?
Periksa status toggle log:
boolean enabled = LogHub.isLogEnabled(); boolean consoleEnabled = LogHub.isConsoleLogEnabled(); int level = LogHub.getLogLevel();Lihat output Logcat:
Filter log menggunakan
tag:AliPlayerKit.Periksa jumlah pendengar:
Anda dapat memeriksa jumlah pendengar yang terdaftar menggunakan refleksi (hanya untuk debugging). Verifikasi bahwa pendengar didaftarkan dan dihapus dengan benar.