Pengelogan di C# dan .NET
.NET mendukung pengelogan terstruktur berkinerja tinggi melalui ILogger API untuk membantu memantau perilaku aplikasi dan mendiagnosis masalah. Log dapat ditulis ke tujuan yang berbeda dengan mengonfigurasi penyedia pengelogan yang berbeda. Penyedia pengelogan dasar juga bawaan dan ada banyak penyedia pihak ketiga yang tersedia.
Memulai
Contoh pertama ini menunjukkan dasar-dasarnya, tetapi hanya cocok untuk aplikasi konsol sepele. Aplikasi konsol sampel ini bergantung pada paket NuGet berikut:
Di bagian berikutnya, Anda akan melihat cara meningkatkan kode dengan mempertimbangkan skala, performa, konfigurasi, dan pola pemrograman umum.
using Microsoft.Extensions.Logging;
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Contoh sebelumnya:
- Membuat sebuah ILoggerFactory. Menyimpan
ILoggerFactory
semua konfigurasi yang menentukan tempat pesan log dikirim. Dalam hal ini, Anda mengonfigurasi penyedia pengelogan konsol sehingga pesan log ditulis ke konsol. -
ILogger Membuat dengan kategori bernama "Program". Kategori adalah
string
yang terkait dengan setiap pesan yang dicatat olehILogger
objek. Ini digunakan untuk mengelompokkan pesan log dari kelas (atau kategori) yang sama bersama-sama saat mencari atau memfilter log. -
LogInformation Panggilan untuk mencatat pesan di tingkat tersebut
Information
. Tingkat log menunjukkan tingkat keparahan peristiwa yang dicatat dan digunakan untuk memfilter pesan log yang kurang penting. Entri log juga menyertakan templat"Hello World! Logging is {Description}."
pesan dan pasanganDescription = fun
kunci-nilai . Nama kunci (atau tempat penampung) berasal dari kata di dalam kurung kurawal dalam templat dan nilai berasal dari argumen metode yang tersisa.
File proyek untuk contoh ini mencakup dua paket NuGet:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.3" />
</ItemGroup>
</Project>
Tip
Semua contoh pengelogan kode sumber tersedia di Browser Sampel untuk diunduh. Untuk informasi selengkapnya, lihat Menelusuri sampel kode: Pengelogan di .NET.
Pengelogan di aplikasi non-sepele
Ada beberapa perubahan yang harus Anda pertimbangkan untuk membuat contoh sebelumnya saat pengelogan dalam skenario yang kurang sepele:
Jika aplikasi Anda menggunakan Dependency Injection (DI) atau host seperti ASP. WebApplication NET atau Host Generik maka Anda harus menggunakan
ILoggerFactory
objek danILogger
dari kontainer DI masing-masing daripada membuatnya secara langsung. Untuk informasi selengkapnya, lihat Integrasi dengan DI dan Host.Pembuatan sumber waktu kompilasi pengelogan Pembuatan sumber pengelogan menawarkan performa yang lebih baik, pengetikan yang lebih kuat, dan menghindari penyebaran
string
konstanta di seluruh metode Anda. Tradeoff adalah bahwa menggunakan teknik ini membutuhkan sedikit lebih banyak kode.
using Microsoft.Extensions.Logging;
internal partial class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
LogStartupMessage(logger, "fun");
}
[LoggerMessage(Level = LogLevel.Information, Message = "Hello World! Logging is {Description}.")]
static partial void LogStartupMessage(ILogger logger, string description);
}
- Praktik yang direkomendasikan untuk nama kategori log adalah menggunakan nama kelas yang sepenuhnya memenuhi syarat yang membuat pesan log. Ini membantu menghubungkan pesan log kembali ke kode yang menghasilkannya dan menawarkan tingkat kontrol yang baik saat memfilter log.
CreateLogger
Type
menerima untuk membuat penamaan ini mudah dilakukan.
using Microsoft.Extensions.Logging;
internal class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger<Program>();
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
}
}
- Jika Anda tidak menggunakan log konsol sebagai solusi pemantauan produksi anda, tambahkan penyedia pengelogan yang anda rencanakan untuk digunakan. Misalnya, Anda dapat menggunakan OpenTelemetry untuk mengirim log melalui OTLP (protokol OpenTelemetry):
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using ILoggerFactory factory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});
});
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Integrasi dengan host dan injeksi dependensi
Jika aplikasi Anda menggunakan Dependency Injection (DI) atau host seperti ASP. WebApplication NET atau Host Generik maka Anda harus menggunakan ILoggerFactory
objek dan ILogger
dari kontainer DI daripada membuatnya secara langsung.
Mendapatkan ILogger dari DI
Contoh ini mendapatkan objek ILogger di aplikasi yang dihosting menggunakan API Minimal ASP.NET:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
var handler = app.Services.GetRequiredService<ExampleHandler>();
app.MapGet("/", handler.HandleRequest);
app.Run();
partial class ExampleHandler(ILogger<ExampleHandler> logger)
{
public string HandleRequest()
{
LogHandleRequest(logger);
return "Hello World";
}
[LoggerMessage(LogLevel.Information, "ExampleHandler.HandleRequest was called")]
public static partial void LogHandleRequest(ILogger logger);
}
Contoh sebelumnya:
- Membuat layanan singleton yang disebut
ExampleHandler
dan memetakan permintaan web masuk untuk menjalankanExampleHandler.HandleRequest
fungsi. - Baris 12 mendefinisikan konstruktor utama untuk ExampleHandler, fitur yang ditambahkan dalam C# 12. Menggunakan konstruktor C# gaya lama akan bekerja sama baiknya tetapi sedikit lebih verbose.
- Konstruktor mendefinisikan parameter jenis
ILogger<ExampleHandler>
. ILogger<TCategoryName> berasal dari ILogger dan menunjukkan kategoriILogger
mana yang dimiliki objek. Kontainer DI menemukan dengan kategori yangILogger
benar dan menyediakannya sebagai argumen konstruktor. Jika belum adaILogger
dengan kategori tersebut, kontainer DI secara otomatis membuatnya dariILoggerFactory
penyedia layanan. - Parameter
logger
yang diterima dalam konstruktor digunakan untuk pengeloganHandleRequest
dalam fungsi.
ILoggerFactory yang disediakan host
Penyusun host menginisialisasi konfigurasi default, lalu menambahkan objek yang dikonfigurasi ILoggerFactory
ke kontainer DI host saat host dibuat. Sebelum host dibuat, Anda dapat menyesuaikan konfigurasi pengelogan melalui HostApplicationBuilder.Logging, , WebApplicationBuilder.Loggingatau API serupa di host lain. Host juga menerapkan konfigurasi pengelogan dari sumber konfigurasi default sebagai variabel appsettings.json dan lingkungan. Untuk informasi selengkapnya, lihat Konfigurasi di .NET.
Contoh ini diperluas pada yang sebelumnya untuk menyesuaikan yang ILoggerFactory
disediakan oleh WebApplicationBuilder
. Ini menambahkan OpenTelemetry sebagai penyedia pengelogan yang mengirimkan log melalui OTLP (protokol OpenTelemetry):
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter());
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
Membuat ILoggerFactory dengan DI
Jika Anda menggunakan kontainer DI tanpa host, gunakan AddLogging untuk mengonfigurasi dan menambahkan ILoggerFactory
ke kontainer.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
// Add services to the container including logging
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddSingleton<ExampleService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Get the ExampleService object from the container
ExampleService service = serviceProvider.GetRequiredService<ExampleService>();
// Do some pretend work
service.DoSomeWork(10, 20);
class ExampleService(ILogger<ExampleService> logger)
{
public void DoSomeWork(int x, int y)
{
logger.LogInformation("DoSomeWork was called. x={X}, y={Y}", x, y);
}
}
Contoh sebelumnya:
- Membuat kontainer layanan DI yang berisi yang dikonfigurasi
ILoggerFactory
untuk menulis ke konsol - Menambahkan singleton
ExampleService
ke kontainer - Membuat instans dari
ExampleService
kontainer DI yang juga secara otomatis membuatILogger<ExampleService>
untuk digunakan sebagai argumen konstruktor. - Dipanggil
ExampleService.DoSomeWork
yang menggunakanILogger<ExampleService>
untuk mencatat pesan ke konsol.
Mengonfigurasi pengelogan
Konfigurasi pengelogan diatur dalam kode atau melalui sumber eksternal, seperti file konfigurasi dan variabel lingkungan. Menggunakan konfigurasi eksternal bermanfaat jika memungkinkan karena dapat diubah tanpa membangun kembali aplikasi. Namun, beberapa tugas, seperti mengatur penyedia pengelogan, hanya dapat dikonfigurasi dari kode.
Mengonfigurasi pengelogan tanpa kode
Untuk aplikasi yang menggunakan host, konfigurasi pengelogan umumnya disediakan oleh "Logging"
bagian appsettings.{Environment}
.json file. Untuk aplikasi yang tidak menggunakan host, sumber konfigurasi eksternal disiapkan secara eksplisit atau dikonfigurasi dalam kode sebagai gantinya.
Appsetting berikut . file Development.json dihasilkan oleh templat layanan .NET Worker:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Dalam JSON sebelumnya:
- Kategori
"Default"
tingkat log ,"Microsoft"
, dan"Microsoft.Hosting.Lifetime"
ditentukan. - Nilai
"Default"
diterapkan ke semua kategori yang tidak ditentukan lain, secara efektif membuat semua nilai default untuk semua kategori"Information"
. Anda dapat mengambil alih perilaku ini dengan menentukan nilai untuk kategori. - Kategori
"Microsoft"
berlaku untuk semua kategori yang dimulai dengan"Microsoft"
. - Kategori
"Microsoft"
mencatat pada tingkatWarning
log dan yang lebih tinggi. - Kategori
"Microsoft.Hosting.Lifetime"
ini lebih spesifik daripada"Microsoft"
kategori, sehingga"Microsoft.Hosting.Lifetime"
log kategori pada tingkat"Information"
log dan lebih tinggi. - Penyedia log tertentu tidak ditentukan, jadi
LogLevel
berlaku untuk semua penyedia pengelogan yang diaktifkan kecuali untuk Windows EventLog.
Properti Logging
dapat memiliki LogLevel dan properti penyedia log.
LogLevel
menentukan tingkat minimum yang akan dicatat untuk kategori yang dipilih. Di JSON sebelumnya, Information
dan Warning
tingkat log ditentukan.
LogLevel
menunjukkan tingkat keparahan log dan memiliki rentang 0 hingga 6:
Trace
= 0, Debug
= 1, Information
= 2, Warning
= 3, Error
= 4, Critical
= 5, dan None
= 6.
Bila LogLevel
ditetapkan, pengelogan diaktifkan untuk pesan pada tingkat yang ditentukan dan lebih tinggi. Di JSON sebelumnya, Default
kategori dicatat dan Information
lebih tinggi. Misalnya, pesan Information
, Warning
, Error
, dan Critical
dicatat. Jika tidak ada LogLevel
yang ditentukan, pengelogan diatur ke default, yakni tingkat Information
. Untuk informasi lebih lanjut, lihat Tingkat log.
Properti penyedia dapat menentukan properti LogLevel
.
LogLevel
di bawah penyedia menentukan tingkat yang perlu dicatat untuk penyedia tersebut, dan menimpa pengaturan log non-penyedia. Pertimbangkan file appsettings.json berikut:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting": "Trace"
}
},
"EventSource": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Pengaturan di Logging.{ProviderName}.LogLevel
menimpa pengaturan di Logging.LogLevel
. Di JSON sebelumnya, Debug
tingkat log default penyedia diatur ke Information
:
Logging:Debug:LogLevel:Default:Information
Pengaturan sebelumnya menetapkan tingkat log Information
untuk setiap kategori Logging:Debug:
kecuali Microsoft.Hosting
. Ketika kategori tertentu dicantumkan, kategori tersebut menimpa kategori default. Di JSON sebelumnya, Logging:Debug:LogLevel
kategori "Microsoft.Hosting"
dan "Default"
ambil alih pengaturan di Logging:LogLevel
Tingkat log minimum dapat ditentukan untuk salah satu dari:
- Penyedia tertentu: Misalnya,
Logging:EventSource:LogLevel:Default:Information
- Kategori tertentu: Misalnya,
Logging:LogLevel:Microsoft:Warning
- Semua penyedia dan semua kategori:
Logging:LogLevel:Default:Warning
Setiap log di bawah tingkat minimum tidak:
- Diteruskan ke penyedia.
- Dicatat atau ditampilkan.
Untuk menyembunyikan semua log, tentukan LogLevel.None.
LogLevel.None
memiliki nilai 6, yang lebih tinggi dari LogLevel.Critical
(5).
Jika penyedia mendukung cakupan log, IncludeScopes
menunjukkan apakah cakupan diaktifkan. Untuk informasi selengkapnya, lihat cakupan log aktivitas .
File appsettings.json berikut berisi pengaturan untuk semua penyedia bawaan:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.Extensions.Hosting": "Warning",
"Default": "Information"
}
},
"EventSource": {
"LogLevel": {
"Microsoft": "Information"
}
},
"EventLog": {
"LogLevel": {
"Microsoft": "Information"
}
},
"AzureAppServicesFile": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Warning"
}
},
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
Dalam sampel sebelumnya:
- Kategori dan tingkat bukanlah nilai yang disarankan. Sampel disediakan untuk menunjukkan semua penyedia default.
- Pengaturan di
Logging.{ProviderName}.LogLevel
menimpa pengaturan diLogging.LogLevel
. Misalnya, tingkat diDebug.LogLevel.Default
menggantikan tingkat diLogLevel.Default
. - Alias setiap penyedia digunakan. Setiap penyedia mendefinisikan alias yang dapat digunakan dalam konfigurasi, yang menggantikan nama jenis yang sepenuhnya memenuhi syarat. Alias penyedia bawaan adalah:
Console
Debug
EventSource
EventLog
AzureAppServicesFile
AzureAppServicesBlob
ApplicationInsights
Tetapkan tingkat log berdasarkan baris perintah, variabel lingkungan, dan konfigurasi lainnya
Tingkat log dapat diatur oleh penyedia konfigurasi mana pun. Misalnya, Anda dapat membuat variabel lingkungan yang bertahan bernama Logging:LogLevel:Microsoft
dengan nilai Information
.
Buat dan tetapkan variabel lingkungan yang bertahan, mengingat nilai tingkat log.
:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M
Dalam instans baru Prompt Perintah, baca variabel lingkungan.
:: Prints the env var value
echo %Logging__LogLevel__Microsoft%
Pengaturan lingkungan sebelumnya dipertahankan di lingkungan. Untuk menguji pengaturan saat menggunakan aplikasi yang dibuat dengan templat layanan .NET Worker, gunakan dotnet run
perintah di direktori proyek setelah variabel lingkungan ditetapkan.
dotnet run
Tip
Setelah menetapkan variabel lingkungan, mulai ulang lingkungan pengembangan terpadu (IDE) Anda untuk memastikan bahwa variabel lingkungan yang baru ditambahkan tersedia.
Pada Azure App Service, pilih Pengaturan aplikasi baru di halaman Pengaturan > Konfigurasi. Pengaturan aplikasi Azure App Service:
- Dienkripsi saat tidak aktif dan ditransmisikan melalui saluran terenkripsi.
- Diekspos sebagai variabel lingkungan.
Untuk informasi selengkapnya tentang mengatur nilai konfigurasi .NET menggunakan variabel lingkungan, lihat variabel lingkungan.
Mengonfigurasi pengelogan dengan kode
Untuk mengonfigurasi pengelogan dalam kode, gunakan ILoggingBuilder API. Ini dapat diakses dari berbagai tempat:
- Saat membuat secara langsung, konfigurasikan
ILoggerFactory
di LoggerFactory.Create. - Saat menggunakan DI tanpa host, konfigurasikan di LoggingServiceCollectionExtensions.AddLogging.
- Saat menggunakan host, konfigurasikan dengan HostApplicationBuilder.Logging, WebApplicationBuilder.Logging atau API spesifik host lainnya.
Contoh ini menunjukkan pengaturan penyedia pengelogan konsol dan beberapa filter.
using Microsoft.Extensions.Logging;
using var loggerFactory = LoggerFactory.Create(static builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogDebug("Hello {Target}", "Everyone");
Dalam contoh AddFilter sebelumnya digunakan untuk menyesuaikan tingkat log yang diaktifkan untuk berbagai kategori.
AddConsole digunakan untuk menambahkan penyedia pengelogan konsol. Secara default, log dengan Debug
tingkat keparahan tidak diaktifkan, tetapi karena konfigurasi menyesuaikan filter, pesan debug "Halo Semua Orang" ditampilkan di konsol.
Bagaimana aturan pemfilteran diterapkan
Saat objek ILogger<TCategoryName> dibuat, objek ILoggerFactory memilih satu aturan per penyedia untuk diterapkan ke pencatat tersebut. Semua pesan yang ditulis oleh instans ILogger
difilter berdasarkan aturan yang dipilih. Aturan paling spesifik untuk setiap pasangan penyedia dan kategori dipilih dari aturan yang tersedia.
Algoritma berikut digunakan untuk setiap penyedia saat ILogger
dibuat untuk kategori tertentu:
- Pilih semua aturan yang cocok dengan penyedia atau aliasnya. Jika tidak ditemukan kecocokan, pilih semua aturan dengan penyedia yang kosong.
- Dari hasil langkah sebelumnya, pilih aturan dengan awalan kategori yang cocok terpanjang. Jika tidak ada kecocokan yang ditemukan, pilih semua aturan yang tidak menentukan kategori.
- Jika beberapa aturan dipilih, ambil yang terakhir.
- Jika tidak ada aturan yang dipilih, gunakan LoggingBuilderExtensions.SetMinimumLevel(ILoggingBuilder, LogLevel) untuk menentukan tingkat pengelogan minimum.
Kategori log
Saat objek ILogger
dibuat, kategori ditentukan. Kategori tersebut disertakan dengan setiap pesan log yang dibuat oleh instans ILogger
tersebut. String kategori bersifat arbitrer, tetapi konvensinya adalah menggunakan nama kelas yang sepenuhnya memenuhi syarat. Misalnya, dalam aplikasi dengan layanan yang ditentukan seperti objek berikut, kategorinya mungkin "Example.DefaultService"
:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger<DefaultService> _logger;
public DefaultService(ILogger<DefaultService> logger) =>
_logger = logger;
// ...
}
}
Jika kategorisasi lebih lanjut diinginkan, konvensinya adalah menggunakan nama hierarkis dengan menambahkan subkategori ke nama kelas yang sepenuhnya memenuhi syarat, dan secara eksplisit menentukan kategori menggunakan LoggerFactory.CreateLogger:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger _logger;
public DefaultService(ILoggerFactory loggerFactory) =>
_logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");
// ...
}
}
Panggilan CreateLogger
dengan nama tetap dapat berguna saat digunakan dalam beberapa kelas/jenis sehingga peristiwa dapat diatur berdasarkan kategori.
ILogger<T>
sama dengan memanggil CreateLogger
, dengan nama jenis T
yang sepenuhnya memenuhi syarat.
Tingkat log
Tabel berikut mencantumkan nilai LogLevel, metode ekstensi Log{LogLevel}
yang praktis, dan penggunaan yang disarankan:
LogLevel | Nilai | Metode | Deskripsi |
---|---|---|---|
Bekas | 0 | LogTrace | Berisi pesan paling terperinci. Pesan ini mungkin berisi data aplikasi yang sensitif. Pesan-pesan ini dinonaktifkan secara default dan tidak boleh diaktifkan dalam produksi. |
Debug | 1 | LogDebug | Untuk penelusuran kesalahan dan pengembangan. Gunakan dengan hati-hati dalam produksi karena volume yang tinggi. |
Informasi | 2 | LogInformation | Melacak alur umum aplikasi. Mungkin memiliki nilai jangka panjang. |
Peringatan | 3 | LogWarning | Untuk peristiwa yang tidak normal atau tidak terduga. Biasanya menyertakan kesalahan atau kondisi yang tidak menyebabkan aplikasi gagal. |
Kesalahan | 4 | LogError | Untuk kesalahan dan pengecualian yang tidak dapat ditangani. Pesan-pesan ini menunjukkan kegagalan dalam operasi atau permintaan saat ini, bukan kegagalan di seluruh aplikasi. |
Kritis | 5 | LogCritical | Untuk kegagalan yang membutuhkan perhatian sesegera mungkin. Contoh: skenario kehilangan data, ruang disk yang habis. |
Tidak | 6 | Menentukan bahwa tidak ada pesan yang harus ditulis. |
Pada tabel sebelumnya, LogLevel
dicantumkan dari tingkat keparahan terendah hingga tertinggi.
Parameter pertama metode Log, LogLevel, menunjukkan tingkat keparahan log. Alih-alih memanggil Log(LogLevel, ...)
, sebagian besar pengembang memanggil metode ekstensi Log{LogLevel}. Metode Log{LogLevel}
ekstensi memanggil Log
metode dan menentukan LogLevel
. Misalnya, dua panggilan pengelogan berikut secara fungsional setara dan menghasilkan log yang sama:
public void LogDetails()
{
var logMessage = "Details for log.";
_logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
_logger.LogInformation(AppLogEvents.Details, logMessage);
}
AppLogEvents.Details
adalah ID peristiwa, dan secara implisit diwakili oleh nilai konstanta Int32 .
AppLogEvents
adalah kelas yang mengekspos berbagai konstanta pengidentifikasi bernama dan ditampilkan di bagian ID peristiwa Log.
Kode berikut membuat log Information
dan Warning
:
public async Task<T> GetAsync<T>(string id)
{
_logger.LogInformation(AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
return result;
}
Dalam kode sebelumnya, parameter pertama Log{LogLevel}
, AppLogEvents.Read
, adalah ID peristiwa Log. Parameter kedua adalah template pesan dengan tempat penampung untuk nilai argumen yang disediakan oleh parameter metode yang tersisa. Parameter metode dijelaskan di bagian templat pesan nanti di artikel ini.
Konfigurasikan tingkat log yang sesuai dan panggil metode yang benar Log{LogLevel}
untuk mengontrol berapa banyak output log yang ditulis ke media penyimpanan tertentu. Contohnya:
- Dalam produksi:
- Pengelogan pada tingkat
Trace
atauDebug
menghasilkan pesan log terperinci dengan volume yang tinggi. Untuk mengontrol biaya dan tidak melebihi batas penyimpanan data, catat pesan tingkatTrace
danDebug
ke penyimpanan data bervolume tinggi dan berbiaya rendah. Pertimbangkan untuk membatasiTrace
danDebug
pada kategori tertentu. - Pengelogan pada tingkat
Warning
sampaiCritical
akan menghasilkan beberapa pesan log.- Batas biaya dan penyimpanan biasanya tidak menjadi masalah.
- Beberapa log memungkinkan fleksibilitas yang lebih besar dalam hal pilihan penyimpanan data.
- Pengelogan pada tingkat
- Dalam pengembangan:
- Atur ke
Warning
. - Tambahkan pesan
Trace
atauDebug
saat memecahkan masalah. Untuk membatasi output, aturTrace
atauDebug
hanya untuk kategori yang sedang diselidiki.
- Atur ke
Set Logging:Console:LogLevel:Microsoft:Information
JSON berikut :
{
"Logging": {
"LogLevel": {
"Microsoft": "Warning"
},
"Console": {
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
ID peristiwa log
Setiap log dapat menentukan pengidentifikasi peristiwa, EventId adalah struktur dengan Id
properti readonly opsional Name
dan . Kode sumber sampel menggunakan AppLogEvents
kelas untuk menentukan ID peristiwa:
using Microsoft.Extensions.Logging;
internal static class AppLogEvents
{
internal static EventId Create = new(1000, "Created");
internal static EventId Read = new(1001, "Read");
internal static EventId Update = new(1002, "Updated");
internal static EventId Delete = new(1003, "Deleted");
// These are also valid EventId instances, as there's
// an implicit conversion from int to an EventId
internal const int Details = 3000;
internal const int Error = 3001;
internal static EventId ReadNotFound = 4000;
internal static EventId UpdateNotFound = 4001;
// ...
}
Tip
Untuk informasi selengkapnya tentang mengonversi int
ke EventId
, lihat Operator EventId.Implicit(Int32 ke EventId).
ID peristiwa mengaitkan serangkaian peristiwa. Misalnya, semua log yang terkait dengan membaca nilai dari repositori mungkin .1001
Penyedia pengelogan dapat mencatat ID peristiwa di bidang ID, dalam pesan pengelogan, atau tidak sama sekali. Penyedia Debug tidak menampilkan ID peristiwa. Penyedia konsol menunjukkan ID peristiwa dalam tanda kurung setelah kategori:
info: Example.DefaultService.GetAsync[1001]
Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
GetAsync(a1b2c3) not found
Beberapa penyedia pengelogan menyimpan ID peristiwa di bidang, yang memungkinkan pemfilteran pada ID.
Template pesan log
Setiap API log menggunakan template pesan. Template pesan dapat berisi tempat penampung yang argumennya disediakan. Gunakan nama untuk tempat penampung, bukan angka. Urutan tempat penampung, bukan namanya, menentukan parameter mana yang digunakan untuk memberikan nilainya. Dalam kode berikut, nama parameter di luar urutan dalam templat pesan:
string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);
Kode sebelumnya membuat pesan log dengan nilai parameter secara berurutan:
Parameter values: param1, param2
Catatan
Berhati-hatilah saat menggunakan beberapa tempat penampung dalam satu templat pesan, karena berbasis ordinal. Nama tidak digunakan untuk meratakan argumen ke tempat penampung.
Pendekatan ini memungkinkan penyedia pengelogan untuk mengimplementasikan pengelogan semantik atau terstruktur. Argumen itu sendiri diteruskan ke sistem pengelogan, bukan hanya template pesan yang diformat. Ini memungkinkan penyedia pengelogan untuk menyimpan nilai parameter sebagai bidang. Pertimbangkan metode pencatat berikut:
_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);
Misalnya, saat mencatat ke Azure Table Storage:
- Setiap entitas Azure Table dapat memiliki properti
ID
danRunTime
. - Tabel dengan properti menyederhanakan kueri pada data yang dicatat. Misalnya, kueri dapat menemukan semua log dalam rentang
RunTime
tertentu tanpa harus menguraikan waktu habis pesan teks.
Pemformatan templat pesan log
Templat pesan log mendukung pemformatan tempat penampung. Templat bebas untuk menentukan format yang valid untuk argumen jenis yang diberikan. Misalnya, pertimbangkan templat pesan pencatat berikut Information
:
_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022
Dalam contoh sebelumnya, DateTimeOffset
instans adalah jenis yang sesuai dengan PlaceHolderName
di templat pesan pencatat. Nama ini bisa apa saja karena nilainya berbasis ordinal.
MMMM dd, yyyy
Format ini valid untuk jenis tersebutDateTimeOffset
.
Untuk informasi selengkapnya tentang DateTime
dan DateTimeOffset
pemformatan, lihat String format tanggal dan waktu kustom.
Contoh
Contoh berikut menunjukkan cara memformat templat pesan menggunakan {}
sintaks tempat penampung. Selain itu, contoh melarikan diri {}
dari sintaks tempat penampung ditunjukkan dengan outputnya. Terakhir, interpolasi string dengan tempat penampung templat juga ditampilkan:
logger.LogInformation("Number: {Number}", 1); // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3); // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5); // {Number}: 5
Tip
- Dalam kebanyakan kasus, Anda harus menggunakan pemformatan templat pesan log saat pengelogan. Penggunaan interpolasi string dapat menyebabkan masalah performa.
- Aturan analisis kode CA2254: Templat harus berupa ekspresi statis membantu memperingatkan Anda ke tempat di mana pesan log Anda tidak menggunakan pemformatan yang tepat.
Pengecualian log
Metode pencatat memiliki overload yang mengambil parameter pengecualian:
public void Test(string id)
{
try
{
if (id is "none")
{
throw new Exception("Default Id detected.");
}
}
catch (Exception ex)
{
_logger.LogWarning(
AppLogEvents.Error, ex,
"Failed to process iteration: {Id}", id);
}
}
Pengelogan pengecualian sifatnya khusus untuk penyedia.
Tingkat log default
Jika tingkat log bawaan tidak diatur, nilai tingkat log defaultnya adalah Information
.
Misalnya, pertimbangkan aplikasi layanan pekerja berikut:
- Dibuat dengan templat .NET Worker.
- appsettings.json dan appsetting. Development.json dihapus atau diganti namanya.
Dengan penyiapan sebelumnya, membuka halaman privasi atau beranda akan menghasilkan banyak pesan Trace
, Debug
, dan Information
dengan Microsoft
dalam nama kategori.
Kode berikut menetapkan tingkat log default ketika tingkat log default tidak diatur dalam konfigurasi:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
await host.RunAsync();
Fungsi filter
Fungsi filter dipanggil untuk semua penyedia dan kategori yang tidak memiliki aturan yang ditetapkan padanya oleh konfigurasi atau kode:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddFilter((provider, category, logLevel) =>
{
return provider.Contains("ConsoleLoggerProvider")
&& (category.Contains("Example") || category.Contains("Microsoft"))
&& logLevel >= LogLevel.Information;
});
using IHost host = builder.Build();
await host.RunAsync();
Kode sebelumnya menampilkan log konsol jika kategori berisi Example
atau Microsoft
dan tingkat log adalah Information
atau yang lebih tinggi.
Cakupan log
Cakupan mengelompokkan serangkaian operasi logis. Pengelompokan ini dapat digunakan untuk melampirkan data yang sama ke setiap log yang dibuat sebagai bagian dari kumpulan. Misalnya, setiap log yang dibuat sebagai bagian dari pemrosesan transaksi dapat menyertakan ID transaksi.
Cakupan:
- Adalah jenis IDisposable yang dikembalikan oleh metode BeginScope.
- Bertahan sampai dibuang.
Penyedia berikut mendukung cakupan:
Gunakan cakupan dengan membungkus panggilan pencatat di blok using
:
public async Task<T> GetAsync<T>(string id)
{
T result;
var transactionId = Guid.NewGuid().ToString();
using (_logger.BeginScope(new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("TransactionId", transactionId),
}))
{
_logger.LogInformation(
AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(
AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
}
return result;
}
JSON berikut memungkinkan cakupan untuk penyedia konsol:
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Warning",
"Default": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
}
Kode berikut memungkinkan cakupan untuk penyedia konsol:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options => options.IncludeScopes = true);
using IHost host = builder.Build();
await host.RunAsync();
Membuat log di Utama
Kode berikut mencatat di Main
dengan mendapatkan instans ILogger
dari DI setelah membangun host:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using IHost host = Host.CreateApplicationBuilder(args).Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Host created.");
await host.RunAsync();
Kode sebelumnya bergantung pada dua paket NuGet:
File proyeknya akan terlihat mirip dengan yang berikut ini:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
</ItemGroup>
</Project>
Tidak ada metode pencatat asinkron
Pengelogan harus dilakukan dengan sangat cepat sehingga tidak sebanding dengan biaya performa dari kode asinkron. Jika datastore pengelogan lambat, jangan menulisnya secara langsung. Pertimbangkan untuk terlebih dahulu menulis pesan log ke penyimpanan cepat, lalu memindahkannya ke penyimpanan lambat nanti. Misalnya, saat mencatat ke SQL Server, jangan lakukan secara langsung dalam metode Log
, karena metode Log
bersifat sinkron. Sebagai gantinya, tambahkan pesan log secara sinkron ke antrean dalam memori dan minta pekerja latar belakang untuk menarik pesan keluar dari antrean untuk melakukan pekerjaan asinkron berupa mendorong data ke SQL Server.
Mengubah tingkat log di aplikasi yang sedang berjalan
Logging API tidak menyertakan skenario untuk mengubah tingkat log saat aplikasi sedang berjalan. Namun, beberapa penyedia konfigurasi mampu untuk memuat ulang konfigurasi, yang langsung berpengaruh pada konfigurasi pengelogan. Misalnya, Penyedia Konfigurasi File memuat ulang konfigurasi pengelogan secara default. Jika konfigurasi diubah dalam kode saat aplikasi berjalan, aplikasi dapat memanggil IConfigurationRoot.Reload untuk memperbarui konfigurasi pengelogan aplikasi.
Paket NuGet
Antarmuka ILogger<TCategoryName> dan ILoggerFactory dan implementasi disertakan dalam sebagian besar .NET SDK sebagai referensi paket implisit. Mereka juga tersedia secara eksplisit dalam paket NuGet berikut ketika tidak direferensikan secara implisit:
- Antarmukanya ada di Microsoft.Extensions.Logging.Abstractions.
- Implementasi defaultnya ada di Microsoft.Extensions.Logging.
Untuk informasi selengkapnya tentang .NET SDK mana yang menyertakan referensi paket implisit, lihat .NET SDK: tabel ke namespace implisit.