- Day 1 - Jumpstart .NET Core
- Day 2 - Building .NET Core Basic Application With Visual Studio 2017
- Day 3 - Building .NET Core Basic Application With Static Files
- Day 4 - Read Configuration Files in .NET Core Application
- Day 5 - Create Shared Library or Packages in .Net Core Application
- Day 6 - Route Concept in .Net Core Application
- Day 7 - Route Concept With MVC Pattern
- Day 8 - URL Rewriting Middleware in Asp.Net Core
- Day 9 - Use Web Socket in Asp.Net Core
- Day 10 - How to Use Localisation in Asp.Net Core
- Day 11 - Configuration API in Asp.Net Core
What's logging and tracing?
Logging (also called tracing) is used to record information about a program's execution for debugging and testing purposes. Developers, testers, and support engineers often use logging and tracing techniques to identify software problems, for post-deployment debugging, monitoring live systems, and auditing purposes.
Logging usually involves writing text messages to log files or sending data to monitoring applications. Advanced and modern logging tools also support logging of complex data structures, call stacks, threading behavior and also support real-time monitoring of applications over a network or on a local machine.
For the above logging and tracing purpose, the below mentioned third party logging framework or library is mainly used which still can be applicable within ASP.NET Core application.
- Log4Net
- NLog
- SeriLog
Built-in ASP.NET Core Logging
ASP.NET Core now has a built-in logging framework which we can use. It is designed as a logging API that developers can use to capture built-in ASP.NET logging as well as for their own custom logging. The logging API supports multiple output providers and is extensible to potentially be able to send your application logging anywhere.
Other logging frameworks like NLog and Serilog have even written providers for it. So, you can use the ILoggerFactory and it ends up working sort of the same. Logging acts as a facade above an actual logging library. By using it in this way, it also allows you to leverage all the power of a library, like NLog, to overcome any limitations the built-in Microsoft.Extensions.Logging API may have. The biggest of those is being able to actually write your logs to a file on disk!
How to add Logging Provider
Actually, logging provider is always required to fire some action to log data which can be displayed in the console or stored within a physical file located in the physical machine or cloud environment. To use a logging provider in ASP.NET Core, we need to install Microsoft.Extensions.Logging.Abstractions package from NuGet Manager. Basically, this package contains two interfaces – ILogger and ILoggerFactory.
ASP.NET Core dependency injection (DI) provides the ILoggerFactory instance. The AddConsole and AddDebug extension methods are defined in the Microsoft.Extensions.Logging.Console and Microsoft.Extensions.Logging.Debug packages. Each extension method calls the ILoggerFactory.AddProvider method, passing in an instance of the provider.
How to create Logs Data
To create logs in the application, we need to get an instance of ILogger object using Dependency Injection and store that data within a field. After this, we need to call the logging methods on those logger objects.
- public class TodoController : Controller
- {
- private readonly ITodoRepository _todoRepository;
- private readonly ILogger _logger;
- public TodoController(ITodoRepository todoRepository,
- ILogger<TodoController> logger)
- {
- _todoRepository = todoRepository;
- _logger = logger;
- }
- …………….
- }
- public IActionResult GetById(string id)
- {
- _logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);
- var item = _todoRepository.Find(id);
- if (item == null)
- {
- _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);
- return NotFound();
- }
- return new ObjectResult(item);
- }
What is Log Category?
A category is specified with each log that we create in our application. The category may be any string, but a best convention is to use the fully qualified name of the class from which the logs are written. For example: "EmployeeApi.Controllers.SaveController".
We specify the category when we create a logger object or request one from DI, and the category is automatically included with every log written by that logger. We can specify the category explicitly or we can use an extension method that derives the category from the type.
- public class TodoController : Controller
- {
- private readonly ITodoRepository _todoRepository;
- private readonly ILogger _logger;
- public TodoController(ITodoRepository todoRepository,
- ILoggerFactory logger)
- {
- _todoRepository = todoRepository;
- _logger = logger.CreateLogger("TodoApi.Controllers.TodoController");
- }
- ………………..
- }
About Log Level
Each time we write a log, we specify its LogLevel as per its importance. The log level indicates the degree of severity or importance. For example, we might write an Information log when a method ends normally; a Warning log when a method returns a 404 return code; and an Error log when you catch an unexpected exception.
- public IActionResult GetById(string id)
- {
- _logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);
- var item = _todoRepository.Find(id);
- if (item == null)
- {
- _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);
- return NotFound();
- }
- return new ObjectResult(item);
- }
The below table defines the different log levels mentioned within ASP.NET Core.
| Log Level | Level value | Description |
| Trace | 0 | For information that is valuable only to a developer debugging an issue. These messages may contain sensitive application data and so should not be enabled in a production environment. Disabled by default. |
| Debug | 1 | For information that has short-term usefulness during development and debugging |
| Information | 2 | For tracking the general flow of the application |
| Warning | 3 | For abnormal or unexpected events in the application flow. These may include errors or other conditions that do not cause the application to stop |
| Error | 4 | For errors and exceptions that cannot be handled. These messages indicate a failure in the current activity or operation (such as the current HTTP request), |
| Critical | 5 | For failures that require immediate attention. Examples: data loss scenarios, out of disk space |
Given below is the built-in Logging Provider in ASP.NET Core.
- Console
- Debug
- EventSource
- EventLog
- TraceSource
- Azure App Service
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Logging;
- using Prog12_Logging.Core;
- using Prog12_Logging.IRepository;
- using Prog12_Logging.Model;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- namespace Prog12_Logging.Controllers
- {
- [Route("api/[controller]")]
- public class TodoController : Controller
- {
- private readonly ITodoRepository _todoRepository;
- private readonly ILogger _logger;
- public TodoController(ITodoRepository todoRepository, ILogger<TodoController> logger)
- {
- _todoRepository = todoRepository;
- _logger = logger;
- }
- [HttpGet]
- public IEnumerable<TodoItem> GetAll()
- {
- using (_logger.BeginScope("Message {HoleValue}", DateTime.Now))
- {
- _logger.LogInformation(LoggingEvents.LIST_ITEMS, "Listing all items");
- EnsureItems();
- }
- return _todoRepository.GetAll();
- }
- [HttpGet("{id}", Name = "GetTodo")]
- public IActionResult GetById(string id)
- {
- _logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);
- var item = _todoRepository.Find(id);
- if (item == null)
- {
- _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);
- return NotFound();
- }
- return new ObjectResult(item);
- }
- [HttpPost]
- public IActionResult Create([FromBody] TodoItem item)
- {
- if (item == null)
- {
- return BadRequest();
- }
- _todoRepository.Add(item);
- _logger.LogInformation(LoggingEvents.INSERT_ITEM, "Item {0} Created", item.Key);
- return CreatedAtRoute("GetTodo", new { controller = "Todo", id = item.Key }, item);
- }
- [HttpPut("{id}")]
- public IActionResult Update(string id, [FromBody] TodoItem item)
- {
- if (item == null || item.Key != id)
- {
- return BadRequest();
- }
- var todo = _todoRepository.Find(id);
- if (todo == null)
- {
- _logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "Update({0}) NOT FOUND", id);
- return NotFound();
- }
- _todoRepository.Update(item);
- _logger.LogInformation(LoggingEvents.UPDATE_ITEM, "Item {0} Updated", item.Key);
- return new NoContentResult();
- }
- [HttpDelete("{id}")]
- public void Delete(string id)
- {
- _todoRepository.Remove(id);
- _logger.LogInformation(LoggingEvents.DELETE_ITEM, "Item {0} Deleted", id);
- }
- private void EnsureItems()
- {
- if (!_todoRepository.GetAll().Any())
- {
- _logger.LogInformation(LoggingEvents.GENERATE_ITEMS, "Generating sample items.");
- for (int i = 1; i < 11; i++)
- {
- _todoRepository.Add(new TodoItem() { Name = "Item " + i });
- }
- }
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- namespace Prog12_Logging.Core
- {
- public class LoggingEvents
- {
- public const int GENERATE_ITEMS = 1000;
- public const int LIST_ITEMS = 1001;
- public const int GET_ITEM = 1002;
- public const int INSERT_ITEM = 1003;
- public const int UPDATE_ITEM = 1004;
- public const int DELETE_ITEM = 1005;
- public const int GET_ITEM_NOTFOUND = 4000;
- public const int UPDATE_ITEM_NOTFOUND = 4001;
- }
- }
- using Prog12_Logging.Model;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- namespace Prog12_Logging.IRepository
- {
- public interface ITodoRepository
- {
- void Add(TodoItem item);
- IEnumerable<TodoItem> GetAll();
- TodoItem Find(string key);
- TodoItem Remove(string key);
- void Update(TodoItem item);
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- namespace Prog12_Logging.Model
- {
- public class TodoItem
- {
- public string Key { get; set; }
- public string Name { get; set; }
- public bool IsComplete { get; set; }
- }
- }
- using Prog12_Logging.IRepository;
- using Prog12_Logging.Model;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- namespace Prog12_Logging.Repository
- {
- public class TodoRepository : ITodoRepository
- {
- static ConcurrentDictionary<string, TodoItem> _todos = new ConcurrentDictionary<string, TodoItem>();
- public IEnumerable<TodoItem> GetAll()
- {
- return _todos.Values;
- }
- public void Add(TodoItem item)
- {
- item.Key = Guid.NewGuid().ToString();
- _todos[item.Key] = item;
- }
- public TodoItem Find(string key)
- {
- TodoItem item;
- _todos.TryGetValue(key, out item);
- return item;
- }
- public TodoItem Remove(string key)
- {
- TodoItem item;
- _todos.TryGetValue(key, out item);
- _todos.TryRemove(key, out item);
- return item;
- }
- public void Update(TodoItem item)
- {
- _todos[item.Key] = item;
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Hosting;
- namespace Prog12_Logging
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- var host = new WebHostBuilder()
- .UseKestrel()
- .UseContentRoot(Directory.GetCurrentDirectory())
- .UseIISIntegration()
- .UseStartup<Startup>()
- .Build();
- host.Run();
- }
- }
- }
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using Prog12_Logging.IRepository;
- using Prog12_Logging.Repository;
- namespace Prog12_Logging
- {
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc();
- services.AddScoped<ITodoRepository, TodoRepository>();
- }
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
- {
- loggerFactory
- .AddConsole()
- .AddDebug();
- app.UseStaticFiles();
- app.UseMvc();
- app.Run(async (context) =>
- {
- var logger = loggerFactory.CreateLogger("TodoApi.Startup");
- logger.LogInformation("No endpoint found for request {path}", context.Request.Path);
- await context.Response.WriteAsync("No endpoint found - try /api/todo.");
- });
- }
- }
- }

prashant vishnoiPosted May 8, 2020, 3:19 AM
What if I need to use ILogger in TodoRepository.cs? We can use constructor injection but what about ConfigureServices() method in startup.cs?
Priyanka KalePosted Feb 7, 2018, 3:25 AM
Very helpful and Great information,I appreciate advise especially coming from a professional. Thanks again and keep up the great work!