Bagikan melalui


Pengelogan di C# dan .NET

.NET mendukung pengelogan terstruktur berkinerja tinggi melalui ILogger API untuk membantu memantau perilaku aplikasi dan mendiagnosis masalah. Konfigurasikan penyedia pengelogan yang berbeda untuk menulis log ke tujuan yang berbeda. Penyedia pengelogan dasar adalah bawaan, dan banyak penyedia pihak ketiga tersedia.

Mulai

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. ILoggerFactory menyimpan semua konfigurasi yang menentukan tempat pesan log dikirim. Dalam hal ini, konfigurasikan penyedia pengelogan konsol sehingga pesan log ditulis ke konsol.
  • Membuat sebuah ILogger dengan kategori bernama "Program". Kategori adalah string yang terkait dengan setiap pesan yang dicatat oleh ILogger objek. Ini mengelompokkan pesan log dari kelas (atau kategori) yang sama bersama-sama saat mencari atau memfilter log.
  • Panggilan LogInformation untuk mencatat pesan pada tingkat Information. Tingkat log menunjukkan tingkat keparahan peristiwa yang dicatat dan memfilter pesan log yang kurang penting. Entri log juga menyertakan template pesan"Hello World! Logging is {Description}." dan pasangan kunci-nilai Description = fun. Nama kunci (atau placeholder) berasal dari kata di dalam kurung kurawal dalam template, 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="10.0.1" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.1" />
  </ItemGroup>

</Project>

Tips

Semua contoh kode sumber pencatatan log tersedia di Sampel Browser untuk diunduh. Untuk informasi selengkapnya, lihat Menelusuri sampel kode: Pengelogan di .NET.

Pengelogan di aplikasi non-sepele

Pertimbangkan untuk menerapkan perubahan ini pada contoh sebelumnya ketika menggunakan skenario yang lebih kompleks.

  • Jika aplikasi Anda menggunakan Dependency Injection (DI) atau host seperti WebApplication ASP.NET atau Generic Host, gunakan objek ILoggerFactory dan ILogger dari kontainer DI masing-masing daripada membuatnya secara langsung. Untuk informasi selengkapnya, lihat Integrasi dengan DI dan Host.

  • Biasanya, pencatatan dengan generasi sumber pada waktu kompilasi adalah alternatif yang lebih baik daripada metode ekstensi seperti ILoggerLogInformation. Pembuatan sumber pengelogan menawarkan performa yang lebih baik, pengetikan yang lebih kuat, dan menghindari penyebaran string konstanta di seluruh metode Anda. Komprominya 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 menerima Type 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");
    }
}
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.NET WebApplication atau Host Generik, gunakan ILoggerFactory dan ILogger objek 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 menjalankan ExampleHandler.HandleRequest fungsi.
  • Baris 12 mendefinisikan konstruktor utama untuk ExampleHandler, fitur yang ditambahkan dalam C# 12. Menggunakan konstruktor C# gaya lama bekerja sama baiknya tetapi sedikit lebih verbose.
  • Konstruktor mendefinisikan parameter jenis ILogger<ExampleHandler>. ILogger<TCategoryName> berasal dari ILogger dan menunjukkan kategori ILogger mana yang dimiliki objek. Kontainer DI menemukan elemen ILogger dengan kategori yang benar dan menyediakannya sebagai argumen pada konstruktor. Jika belum ada ILogger dengan kategori tersebut, kontainer DI secara otomatis membuatnya dari ILoggerFactory penyedia layanan.
  • Parameter logger yang diterima dalam konstruktor digunakan untuk pencatatan log di fungsi HandleRequest.

ILoggerFactory yang disediakan oleh host

Penyusun host menginisialisasi konfigurasi default, lalu menambahkan objek yang dikonfigurasi ILoggerFactory ke kontainer DI host saat host dibuat. Sebelum host dibuat, sesuaikan konfigurasi pengelogan melalui HostApplicationBuilder.Logging, , WebApplicationBuilder.Loggingatau API serupa pada host lain. Host juga menerapkan konfigurasi pengelogan dari sumber konfigurasi default seperti appsettings.json dan variabel lingkungan. Untuk informasi selengkapnya, lihat Konfigurasi di .NET.

Contoh ini mengembangkan yang sebelumnya untuk menyesuaikan ILoggerFactory yang 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 ILoggerFactory yang dikonfigurasi untuk menulis ke konsol
  • Menambahkan singleton ExampleService ke kontainer
  • Membuat instans dari ExampleService di dalam kontainer DI, yang juga secara otomatis membuat ILogger<ExampleService> untuk digunakan sebagai argumen konstruktor.
  • Dipanggil ExampleService.DoSomeWork, yang menggunakan ILogger<ExampleService> untuk merekam pesan ke dalam konsol.

Mengonfigurasi pengelogan

Atur konfigurasi pengelogan dalam kode atau melalui sumber eksternal, seperti file konfigurasi dan variabel lingkungan. Menggunakan konfigurasi eksternal bermanfaat jika memungkinkan karena Anda dapat mengubahnya 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, bagian "Logging"appsettings.{Environment}.json file umumnya menyediakan konfigurasi pengelogan. Untuk aplikasi yang tidak menggunakan host, siapkan sumber konfigurasi eksternal secara eksplisit atau konfigurasikan dalam kode sebagai gantinya .

File appsettings.Development.json berikut 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" berlaku untuk semua kategori yang tidak ditentukan sebaliknya, secara efektif membuat semua nilai default untuk semua kategori "Information". Ambil alih perilaku ini dengan menentukan nilai untuk kategori.
  • Kategori "Microsoft" berlaku untuk semua kategori yang dimulai dengan "Microsoft".
  • Kategori "Microsoft" mencatat pada tingkat log Warning dan lebih tinggi.
  • Kategori "Microsoft.Hosting.Lifetime" lebih spesifik daripada kategori "Microsoft", sehingga kategori "Microsoft.Hosting.Lifetime" mencatat pada tingkat log "Information" dan lebih tinggi.
  • Penyedia log tertentu tidak ditentukan, jadi LogLevel berlaku untuk semua penyedia pengelogan yang diaktifkan kecuali untuk Windows EventLog.

Properti Logging dapat mencakup LogLevel serta properti penyedia log. LogLevel menentukan tingkat minimum yang akan dicatat untuk kategori yang dipilih. Di JSON sebelumnya, tingkat log Information dan Warning 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, kategori Default dicatat untuk Information dan 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 bernama LogLevel. LogLevel untuk penyedia menentukan level pencatatan untuk penyedia tersebut, dan menggantikan pengaturan log yang bukan untuk 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 menggantikan 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 menggantikan kategori default. Di JSON sebelumnya, Logging:Debug:LogLevel kategori "Microsoft.Hosting" dan "Default" ambil alih pengaturan di Logging:LogLevel.

Tentukan tingkat log minimum untuk salah satu dari ini:

  • Penyedia tertentu: Misalnya, Logging:EventSource:LogLevel:Default:Information
  • Kategori tertentu: Misalnya, Logging:LogLevel:Microsoft:Warning
  • Semua penyedia dan semua kategori: Logging:LogLevel:Default:Warning

Log apa pun di bawah tingkat minimum tidak ada:

  • 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 mereka 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 tingkatan bukan nilai yang disarankan. Sampel menunjukkan semua penyedia default.
  • Pengaturan di Logging.{ProviderName}.LogLevel menggantikan pengaturan di Logging.LogLevel. Misalnya, tingkat di Debug.LogLevel.Default menggantikan tingkat di LogLevel.Default.
  • Alias dari setiap penyedia digunakan. Setiap penyedia menentukan alias yang dapat Anda gunakan dalam konfigurasi sebagai pengganti 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

Atur tingkat log menggunakan salah satu penyedia konfigurasi. Misalnya, buat variabel lingkungan yang bertahan bernama Logging:LogLevel:Microsoft dengan nilai Information.

Buat dan tetapkan variabel lingkungan yang bertahan, berdasarkan nilai tingkat log.

:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M

Dalam jendela baru Command Prompt, baca variabel lingkungan.

:: Prints the env var value
echo %Logging__LogLevel__Microsoft%

Pengaturan lingkungan sebelumnya tetap ada 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

Tips

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. Anda dapat mengaksesnya dari berbagai tempat:

Contoh ini menunjukkan pengaturan penyedia pencatatan 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 sebelumnya, AddFiltermenyesuaikan tingkat log yang diaktifkan untuk berbagai kategori. AddConsole 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. ILogger Instans memfilter semua pesan yang ditulisnya 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 berguna saat digunakan dalam beberapa kelas/jenis sehingga peristiwa dapat diatur berdasarkan kategori.

ILogger<T> setara dengan memanggil CreateLogger dengan nama tipe lengkap dari T.

Tingkat log

Tabel berikut mencantumkan nilai LogLevel, metode ekstensi Log{LogLevel} yang praktis, dan penggunaan yang disarankan:

LogLevel Nilai Metode Deskripsi
Jejak 0 LogTrace Berisi pesan paling terperinci. Pesan-pesan ini mungkin berisi data aplikasi sensitif. Pesan-pesan ini dinonaktifkan secara bawaan dan tidak boleh diaktifkan dalam produksi.
Awakutu 1 LogDebug Untuk debugging 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}. Log{LogLevel} metode ekstensi memanggil metode Log 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 Log peristiwa.

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 lain. 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 atau Debug menghasilkan pesan log terperinci dengan volume yang tinggi. Untuk mengontrol biaya dan tidak melebihi batas penyimpanan data, catat pesan tingkat Trace dan Debug ke penyimpanan data bervolume tinggi dan berbiaya rendah. Pertimbangkan untuk membatasi Trace dan Debug pada kategori tertentu.
    • Pengelogan pada tingkat Warning sampai Critical akan menghasilkan beberapa pesan log.
      • Batas biaya dan penyimpanan biasanya tidak menjadi masalah.
      • Beberapa log memungkinkan fleksibilitas lebih besar dalam pilihan penyimpanan data.
  • Dalam pengembangan:
    • Atur ke Warning.
    • Tambahkan pesan Trace atau Debug saat memecahkan masalah. Untuk membatasi output, atur Trace atau Debug hanya untuk kategori yang sedang diselidiki.

Logging:Console:LogLevel:Microsoft:Information JSON berikut adalah:

{
    "Logging": {
        "LogLevel": {
            "Microsoft": "Warning"
        },
        "Console": {
            "LogLevel": {
                "Microsoft": "Information"
            }
        }
    }
}

ID acara log

Setiap log dapat menentukan pengidentifikasi peristiwa, EventId adalah sebuah struktur dengan Id dan properti hanya baca opsional Name. 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;

    // ...
}

Tips

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 adalah 1001.

Penyedia pengelogan mungkin 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 pencatatan menyimpan ID kejadian dalam sebuah bidang, yang memungkinkan pemfilteran berdasarkan ID.

Template pesan log

Setiap API log menggunakan template pesan. Template pesan dapat berisi placeholder untuk mana argumen disediakan. Gunakan nama untuk pengganti, bukan angka. Urutan tempat penampung, bukan namanya, menentukan parameter mana yang digunakan untuk menetapkan nilai. 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 placeholder dalam satu templat pesan, karena berbasis urutan ordinal. Nama tidak digunakan untuk menyelaraskan argumen dengan tempat penampung.

Pendekatan ini memungkinkan penyedia pengelogan menerapkan 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 dan RunTime.
  • 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 placeholder. Templat dapat 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, instance DateTimeOffset adalah tipe yang sesuai dengan PlaceHolderName dalam template pesan log. Nama ini bisa apa saja karena nilainya berbasis ordinal. MMMM dd, yyyy Format ini valid untuk jenis tersebutDateTimeOffset.

Untuk informasi selengkapnya tentang pemformatan DateTime dan DateTimeOffset, lihat string format tanggal dan waktu khusus.

Contoh

Contoh berikut menunjukkan cara memformat templat pesan menggunakan sintaksis placeholder {}. Selain itu, sebuah contoh bagaimana mengeksekusi sintaks tempat penampung {} ditunjukkan dengan hasilnya. Terakhir, interpolasi string dengan penempatan placeholder menggunakan templat juga ditampilkan.

logger.LogInformation("Number: {Number}", 1);               // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3);           // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5);    // {Number}: 5

Tips

  • 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 pada Log

Metode logger memiliki overload yang menerima 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);
    }
}

Pencatatan pengecualian bersifat spesifik untuk penyedia.

Tingkat log default

Jika tingkat log default tidak diatur, nilai tingkat log default 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 mengatur tingkat log default saat 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 sekumpulan operasi logis. Pengelompokan ini dapat melampirkan data yang sama ke setiap log yang dibuat sebagai bagian dari set. Misalnya, setiap log yang dibuat sebagai bagian dari pemrosesan transaksi dapat menyertakan ID transaksi.

Cakupan:

Penyedia berikut mendukung ruang lingkup:

Gunakan lingkup dengan membungkus pemanggilan logger dalam 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 lingkup 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.AddSimpleConsole(options => options.IncludeScopes = true);

using IHost host = builder.Build();

await host.RunAsync();

Buat log di Utama

Kode berikut melakukan login ke Main dengan mendapatkan instans ILogger melalui 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 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 pencatatan log lambat, jangan menulis ke dalamnya 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 dapat memuat ulang konfigurasi, yang langsung berpengaruh pada konfigurasi pengelogan. Misalnya, Penyedia Konfigurasi File memuat ulang konfigurasi log secara default. Jika Anda mengubah konfigurasi 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:

Untuk informasi selengkapnya tentang .NET SDK mana yang menyertakan referensi paket implisit, lihat .NET SDK: tabel ke namespace implisit.

Lihat juga