Logging adalah pencatatan kejadian pada waktu program berjalan, mulai dari alur normal sampai kegagalan yang perlu diselidiki setelah kejadian itu lewat. .NET menyediakan abstraksi ILogger beserta keluarga provider yang meneruskan catatan tersebut ke konsol, berkas, atau layanan pemantauan. Topik ini membahas kontrak ILogger, tingkat keparahan log, logging terstruktur, dan penyaringan berdasarkan tingkat, dengan demo yang memakai provider kustom sederhana agar keluaran eksekusinya tetap terukur.
ILogger sebagai kontrak logging#
ILogger adalah antarmuka dari package Microsoft.Extensions.Logging yang mendefinisikan satu metode Log generik, sedangkan metode yang lebih nyaman seperti LogInformation, LogWarning, dan LogError merupakan perluasan (extension method) di atasnya. Setiap pemanggilan membawa tingkat keparahan (log level), nama kategori, dan isi pesan, sehingga kode aplikasi hanya berbicara pada kontraknya dan tidak mengetahui tujuan akhir catatannya. Metode Log yang lengkap juga menerima pengenal peristiwa bertipe EventId dan objek Exception yang terpisah dari pesannya, dan keduanya diteruskan ke provider apa adanya. Pemisahan ini membuat arah penulisan log dapat diubah tanpa menyentuh kode yang menulisnya.
Kategori logger menandai asal sebuah catatan, dan pada praktiknya diambil dari nama kelas pemakainya melalui ILogger<T>. Nama kelas PengukurSuhu menghasilkan kategori bertuliskan PengukurSuhu, sehingga catatan dari kelas berbeda dapat dipilah saat dibaca. Tingkat keparahan yang tersedia diurutkan dari yang paling rinci sampai yang paling berat, sedangkan nilai None bukan tingkat catatan melainkan penanda ambang yang menyembunyikan semuanya.
| Tingkat | Nilai | Kegunaan |
|---|---|---|
| Trace | 0 | Jejak paling rinci untuk penyelidikan lokal |
| Debug | 1 | Informasi pengembangan yang tidak perlu di production |
| Information | 2 | Kejadian alur normal yang patut dicatat |
| Warning | 3 | Kejadian tidak lazim yang masih dapat pulih sendiri |
| Error | 4 | Kegagalan operasi yang menghentikan satu alur kerja |
| Critical | 5 | Kegagalan yang menuntut perhatian segera |
| None | 6 | Penanda untuk menyembunyikan seluruh catatan |
Logging terstruktur#
Logging terstruktur (structured logging) menuliskan pesan sebagai templat dengan placeholder bernama beserta nilainya, bukan sebagai satu teks jadi. Pemanggilan log.LogInformation("Suhu {Ruang} berubah menjadi {Suhu} derajat", "Lab", 24.5) membawa templat itu bersama pasangan Ruang bernilai Lab dan Suhu bernilai 24.5, dan penyusunan teks akhir dilakukan oleh formatter yang dimiliki setiap provider. Pasangan kunci dan nilai tersebut tetap terpisah di dalam struktur data catatan, sehingga provider yang canggih dapat mengindeks dan menyaring log berdasarkan nilai Ruang tanpa mengurai teksnya.
Kebiasaan yang harus dihindari adalah membangun teksnya sendiri dengan interpolasi string sebelum pemanggilan. Pemanggilan seperti log.LogInformation($"Suhu {ruang} berubah") mengirim satu teks jadi, sehingga pasangan kunci dan nilainya hilang dan manfaat struktur itu lenyap. Keselarasan antara placeholder dan argumennya juga wajib dijaga, karena placeholder yang tidak mempunyai argumen pendamping memicu FormatException pada saat pesan dirender oleh formatter.
Provider dan demo dengan provider kustom#
Provider adalah penerus catatan log ke tujuan akhirnya, dan satu aplikasi dapat memasang beberapa provider sekaligus. Provider console bawaan pada package Microsoft.Extensions.Logging.Console menulis setiap baris dengan pola seperti info: NamaKategori[0] pesan diawali waktu kejadian dan kode peristiwa, sedangkan format barisnya memuat timestamp yang berubah pada setiap eksekusi. Karena keluaran tutorial pada jalur ini wajib dapat direproduksi, demo berikut memakai provider kustom kecil bernama PencatatBaris yang menulis baris dengan format tetap tanpa waktu, dan cara memasang provider console dijelaskan pada bagian berikutnya.
#:package Microsoft.Extensions.Logging@10.0.0
// Program: menulis catatan log lewat ILogger dengan provider kustom sederhana
using Microsoft.Extensions.Logging;
ILoggerFactory pabrik = LoggerFactory.Create(bangun =>
{
bangun.SetMinimumLevel(LogLevel.Information);
bangun.AddProvider(new PencatatBarisProvider());
});
ILogger<PengukurSuhu> log = pabrik.CreateLogger<PengukurSuhu>();
log.LogInformation("Suhu {Ruang} berubah menjadi {Suhu} derajat", "Lab", 24.5);
log.LogWarning("Sensor {Ruang} tidak merespons dua kali", "Gudang");
try
{
throw new InvalidOperationException("Nilai sensor di luar rentang");
}
catch (InvalidOperationException ex)
{
log.LogError(ex, "Pembacaan {Ruang} gagal diproses", "Kantor");
}
log.LogDebug("Baris ini disembunyikan karena di bawah tingkat minimum");
// provider kustom yang menulis setiap catatan log sebagai satu baris berformat tetap
class PencatatBarisProvider : ILoggerProvider
{
public ILogger CreateLogger(string kategori) => new PencatatBaris(kategori);
public void Dispose() { }
}
class PencatatBaris : ILogger
{
private readonly string kategori;
public PencatatBaris(string kategori) => this.kategori = kategori;
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel tingkat) => true;
public void Log<TState>(
LogLevel tingkat, EventId peristiwa, TState keadaan,
Exception? exception, Func<TState, Exception?, string> formatter)
{
Console.WriteLine($"{tingkat,-7} {kategori}: {formatter(keadaan, exception)}");
if (exception is not null)
{
Console.WriteLine($" {exception.GetType().Name}: {exception.Message}");
}
}
}
class PengukurSuhu { }Jalankan program tersebut dari folder topik dengan perintah berikut.
# aktifkan .NET yang terpasang di sandbox
export DOTNET_ROOT=/home/kal/.dotnet PATH=/home/kal/.dotnet:$PATH DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1
# jalankan program contoh dari folder topik
dotnet run --file Program.csInformation PengukurSuhu: Suhu Lab berubah menjadi 24.5 derajat
Warning PengukurSuhu: Sensor Gudang tidak merespons dua kali
Error PengukurSuhu: Pembacaan Kantor gagal diproses
InvalidOperationException: Nilai sensor di luar rentangKeluaran tersebut memperlihatkan tiga bagian kontrak yang bekerja bersama. Kategori PengukurSuhu berasal dari CreateLogger<PengukurSuhu>(), pesan akhirnya disusun oleh formatter dari templat dan argumennya, dan panggilan LogDebug tidak muncul sama sekali karena tingkat minimum pabrik ditetapkan Information. Pencatatan exception menerima objek exception sebagai argumen tersendiri, sehingga provider dapat menampilkan jenis dan pesannya secara terpisah dari teks catatannya.
Penyaringan dan provider umum#
Penyaringan menentukan catatan mana yang benar-benar dituliskan, dan batas paling sederhana ditetapkan dengan SetMinimumLevel pada pabrik seperti pada demo. Tingkat minimum berarti ambang, sehingga pemanggilan dengan tingkat di bawahnya dibuang sebelum sampai ke provider, sedangkan pemanggilan pada tingkat itu atau di atasnya diteruskan semua. Aturan yang lebih rinci dapat menargetkan kategori tertentu, misalnya menaikkan ambang untuk kategori kerangka kerja sambil menurunkannya untuk kategori aplikasi, dan aturan semacam ini dicatat oleh konfigurasi logging pada aplikasi yang lebih besar.
Provider bawaan yang umum dipakai mencakup console untuk keluaran terminal, Debug untuk jendela debugger dan pelacak, EventSource untuk alat pemantauan sistem, serta EventLog pada Windows. Ekosistem pihak ketiga seperti Serilog dan NLog menyediakan provider dengan tujuan simpan yang lebih kaya, dan semuanya terhubung melalui AddProvider yang sama dengan provider kustom pada demo. Pemasangan provider console pada program satu berkas dilakukan dengan arahan #:package [email protected] diikuti bangun.AddConsole() di dalam LoggerFactory.Create, dan format barisnya memuat timestamp sehingga bentuk lengkapnya cocok dibaca manusia daripada dibandingkan baris per baris.
Kesalahan umum#
- Menggunakan interpolasi string pada pemanggilan log. Teks jadi yang terkirim membuat pasangan kunci dan nilai tidak tersimpan, sehingga penyaringan berdasarkan nilai di provider terstruktur tidak mungkin dilakukan, dan perbaikannya adalah menulis templat dengan placeholder bernama.
- Menulis
Console.WriteLinesebagai pengganti log. Baris tersebut tidak membawa tingkat, kategori, maupun struktur, dan arah tujuannya menempel pada konsol, sehingga pencatatan lewatILoggerdipakai untuk semua kejadian yang perlu diselidiki. - Melewatkan penutupan pabrik logger. Provider yang menulis ke berkas atau layanan menyangga catatannya, sehingga
Disposeatas pabrik dipanggil sebelum program berakhir agar barisan terakhir benar-benar sampai ke tujuannya.
Ringkasan#
ILoggermemisahkan penulis log dari tujuannya, dengan kategori yang lazim diambil dari nama kelas melaluiILogger<T>dan tingkat keparahan dari enumLogLevel.- Logging terstruktur mengirim templat placeholder bernama beserta nilainya, sehingga provider dapat menyimpan pasangan kunci dan nilai tanpa mengurai teks.
- Provider meneruskan catatan ke tujuan akhirnya melalui
AddProvider, mulai dari console dan Debug sampai pustaka pihak ketiga, dan demo memakai provider kustom yang format barisnya tetap. SetMinimumLevelmenyaring catatan sebelum mencapai provider, dan ambangnya dapat dirinci per kategori.
Referensi#
- Logging in C# and .NET — Microsoft Learn — Panduan resmi logging .NET, mulai dari ILogger, kategori, sampai aturan penyaringan.
- Logging providers — Microsoft Learn — Daftar provider bawaan dan cara pemasangannya.
- ILogger interface — Microsoft Learn — Rujukan API kontrak ILogger beserta metode perluasannya.