Logging adalah praktik mencatat informasi penting tentang apa yang terjadi di dalam aplikasi saat berjalan, sangat krusial untuk debugging masalah di production di mana developer tidak bisa langsung menempelkan debugger ke proses yang sedang berjalan secara live.
Serilog adalah salah satu library logging paling populer di ekosistem .NET, menawarkan konsep structured logging yang memungkinkan data log disimpan dalam format terstruktur (bukan sekadar teks biasa), memudahkan pencarian dan analisis log di kemudian hari menggunakan tool seperti Seq atau Elasticsearch.
Artikel ini membahas cara mengintegrasikan Serilog ke ASP.NET Core, konsep structured logging dengan parameter bernama, serta pengaturan sink (tujuan output log) seperti file dan console secara bersamaan.
Mengonfigurasi Serilog di Program.cs
Serilog dikonfigurasi dengan beberapa sink output sekaligus
Structured Logging dengan Parameter Bernama
Parameter bernama disimpan sebagai field terstruktur, bukan string biasa
Level Logging dan Kapan Memakainya
Berbagai level log sesuai tingkat urgensi informasi
Menambahkan Context Enrichment
Enrichment menambahkan informasi kontekstual ke setiap log otomatis
Serilog juga mendukung pencatatan request HTTP secara otomatis lewat middleware UseSerilogRequestLogging, yang mencatat satu baris log ringkas untuk setiap request masuk lengkap dengan path, status code, dan durasi pemrosesan, jauh lebih efisien dibanding mencatat log detail secara manual di setiap controller untuk kebutuhan monitoring dasar semacam ini.
Structured Logging dan Enrichment dengan Serilog
Structured logging: parameter log menjadi field JSON, bukan string tergabung
Perbedaan mendasar antara logging biasa dan structured logging terletak pada bagaimana data tambahan pada pesan log diperlakukan. Menulis _logger.LogInformation($"Order {order.Id} dibuat") menggabungkan nilai menjadi satu string utuh yang sulit difilter nantinya, sedangkan menulis _logger.LogInformation("Order {OrderId} dibuat", order.Id) membuat Serilog menyimpan OrderId sebagai properti terstruktur terpisah yang bisa langsung difilter atau diquery di log viewer seperti Seq atau Elasticsearch.
Enrich.FromLogContext() memungkinkan penambahan properti kontekstual yang otomatis menempel ke semua log dalam satu scope, misalnya CorrelationId yang sama untuk melacak satu request dari controller hingga ke lapisan repository paling dalam. Kombinasi ini sangat membantu saat debugging masalah di production, karena seluruh log yang berkaitan dengan satu request bisa ditelusuri lewat satu identifier yang sama tanpa perlu menebak-nebak urutan kejadian dari timestamp saja.
Memilih format output JSON lewat JsonFormatter, dibandingkan format teks biasa, menjadi penting ketika log dikirim ke sistem agregasi terpusat, karena struktur field yang konsisten memudahkan pembuatan dashboard dan alert otomatis berdasarkan properti tertentu, misalnya menghitung jumlah error per OrderId atau per endpoint dalam rentang waktu tertentu tanpa perlu melakukan parsing string log secara manual.
Mengarahkan Log ke File Rolling dan Seq dengan Multiple Sinks
Satu baris log terdistribusi otomatis ke semua sink yang terdaftar
Serilog dirancang dengan konsep sink, yaitu tujuan akhir ke mana log dikirim, dan satu aplikasi bisa mendaftarkan lebih dari satu sink sekaligus tanpa mengubah cara pemanggilan _logger.LogInformation di kode aplikasi. Pada contoh di atas, satu baris log yang sama otomatis terkirim ke console untuk kebutuhan debugging langsung, ke file untuk arsip lokal, dan ke server Seq untuk kebutuhan pencarian dan analisis terpusat. Setiap sink juga bisa diberi level minimum berbeda, misalnya file hanya mencatat Warning ke atas sedangkan console mencatat semua level termasuk Debug.
WriteTo.File dengan rollingInterval: RollingInterval.Day membuat file log baru setiap hari secara otomatis dengan nama yang mengandung tanggal, sementara retainedFileCountLimit membatasi jumlah file lama yang disimpan agar disk tidak penuh oleh arsip log yang menumpuk tanpa batas. Pengaturan rolling ini penting untuk aplikasi yang berjalan terus-menerus di server production dalam jangka waktu lama. Tanpa batasan retensi semacam ini, volume file log historis bisa terus bertambah sampai akhirnya mengganggu kapasitas penyimpanan server.
Seq sebagai log viewer terpusat memberi antarmuka pencarian berbasis query terhadap properti terstruktur yang sudah dibahas sebelumnya, seperti mencari seluruh log dengan OrderId tertentu dalam hitungan detik tanpa perlu membuka file log satu per satu di server yang berbeda-beda. Pada arsitektur microservice dengan banyak instance aplikasi berjalan bersamaan, sink terpusat seperti Seq menjadi jauh lebih praktis dibanding mengandalkan file log lokal di tiap server. Dashboard dan alert otomatis di Seq juga bisa dikonfigurasi untuk memberi notifikasi ketika jumlah error melebihi ambang batas tertentu dalam rentang waktu singkat.
Mengaktifkan Request Logging Otomatis dengan Serilog
Tanpa memanggil UseSerilogRequestLogging, log bawaan ASP.NET Core untuk satu request yang sama bisa terpecah menjadi beberapa baris terpisah dari komponen internal yang berbeda, seperti routing dan MVC, sehingga cukup menyulitkan saat perlu mencari log yang terkait dengan satu request tertentu di tengah banyaknya baris log lain. Middleware ini merangkum seluruh informasi penting tersebut menjadi satu baris log terstruktur per request.
MessageTemplate pada middleware ini dapat disesuaikan untuk menyertakan property tambahan seperti elapsed time atau status code, yang kemudian tetap bisa difilter dengan mudah di sink seperti Seq atau file log berformat JSON. Penempatan middleware ini sebaiknya diletakkan di awal pipeline agar durasi yang dicatat benar-benar mencerminkan keseluruhan waktu pemrosesan request dari awal sampai akhir, bukan hanya sebagian prosesnya saja.
Kesalahan Umum yang Sering Terjadi
Mencatat Data Sensitif ke dalam Log
Mencatat password, token, atau data kartu kredit secara langsung ke dalam log adalah risiko keamanan serius, karena log seringkali disimpan lebih lama dan diakses oleh lebih banyak orang dibanding database utama aplikasi itu sendiri.
Memakai String Interpolation Alih-alih Parameter Bernama
Menulis _logger.LogInformation($"Produk {produk.Id}") dengan string interpolation C# menghilangkan manfaat structured logging karena nilai sudah digabung menjadi string sebelum sempat diproses sebagai field terpisah oleh Serilog.
Logging Berlebihan pada Level Information di Production
Mencatat terlalu banyak informasi detail pada level Information untuk setiap request bisa membanjiri sistem log dan menyulitkan menemukan informasi yang benar-benar penting di antara volume log yang sangat besar.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Structured logging dengan Serilog membutuhkan sedikit penyesuaian cara menulis pesan log dibanding string interpolation biasa, namun manfaatnya dalam kemampuan pencarian dan analisis log jangka panjang jauh lebih besar, terutama pada aplikasi production dengan volume traffic tinggi.
Menyimpan log ke file lokal sederhana dan cepat untuk setup awal, namun untuk aplikasi yang di-deploy sebagai banyak instance (seperti di Kubernetes), sink terpusat seperti Elasticsearch atau Seq jauh lebih praktis untuk melihat log gabungan dari seluruh instance di satu tempat.
Ringkasan
Serilog dengan structured logging memberikan kemampuan pencatatan yang jauh lebih kaya dibanding logging teks biasa, memudahkan pencarian dan analisis masalah di production. Pilih level logging yang tepat sesuai urgensi, manfaatkan parameter bernama untuk structured data, dan selalu hindari mencatat informasi sensitif ke dalam log.
Seri Belajar .NET Core:
← Sebelumnya: Authorization dan Role Based Access Control
→ Selanjutnya: Exception Handling Global Middleware