Logs record what an application did and what went wrong. They are especially useful when a problem appears only in production. Structured logging keeps the readable message but also records details as named values, so you can search for a particular user, recipe, or kind of event instead of searching through lines of text. section 26.0 section 26.5
In ASP.NET Core, inject ILogger<T> into the class that needs to write a log. Call a method such as LogInformation with a message template and its values. In "Loaded {RecipeCount} recipes", RecipeCount names a captured value; it is not just a gap in the displayed sentence. Placeholders match arguments by position, so supply at least one argument for each placeholder or the call will fail at runtime. section 26.2 section 26.2.3
Listing 26.2 Injecting ILogger into a class and writing a log message
public class IndexModel : PageModel
{
private readonly RecipeService _service;
private readonly ILogger<IndexModel> _log; #1
public ICollection<RecipeSummaryViewModel> Recipes { get; set; }
public IndexModel(
RecipeService service,
ILogger<IndexModel> log) #1
{
_service = service;
_log = log; #1
}
public void OnGet()
{
Recipes = _service.GetRecipes();
_log.LogInformation( #2
"Loaded {RecipeCount} recipes", Recipes.Count); #2
}
}
#1 Injects the generic ILogger<T> using DI, which implements ILogger
#2 Writes an Information-level log. The RecipeCount variable is substituted in the message.
This page handler retrieves recipes, then writes an Information-level log with their count. The named placeholder lets a structured provider retain the count as a value. section 26.2
A warning you can search
A plain warning might say "Could not find recipe with id 3245". A structured version can retain the same readable message alongside fields such as eventLevel, category, eventId, messageTemplate, and recipeId. You can then filter for warnings or for recipeId 3245 without relying on a text match. section 26.5
A named placeholder does not guarantee that every output will expose a searchable field. The default console format displays the substituted message but does not offer key-value searching. Write templates with explicit names anyway: a structured provider can use those captured values later. For JSON console output, call WebApplicationBuilder.Logging.AddJsonConsole(). section 26.2.3
For searchable logs in Seq, install Seq.Extensions.Logging, call builder.Logging.AddSeq(), and run Seq locally. Browse the app to generate logs, then inspect their captured properties in Seq. For details that should accompany every log within a block, use an ILogger.BeginScope scope. Logging providers determine destinations, while log-level filtering controls how much they output; production commonly uses less verbose settings than development. section 26.5.1 section 26.6













