locked
webapi logging with serilog help RRS feed

  • Question

  • User-154169686 posted

    Hi 

    I am using serilog and SEQ in my project web api. I am new to both.

    1) How can I make sure every time I write error, information, debug it should contain ClassName.Method Name. I know I have to create Enrich but not sure how to get ClassName.Method Name

    2) I have created Logger class which has static method which return me logger. Is there any better way such as Dependency inject. so that I can use in multiple classes

    public partial class Logger
    {
    public static ILogger ConfigureLogging()

    {

    return Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .Enrich.WithProperty("Host", host)
    .Enrich.FromLogContext()
    .WriteTo.Seq(serilogUrl)
    .CreateLogger();

    }

    Thursday, September 20, 2018 6:41 AM

All replies

  • User1120430333 posted

    I use Serilog for .NET Core WebAPI  and I use Log4net for non WebAPI.

    So what type of WebAPI are you using? 

    I use Serilog in the .NET Core WebAPI global exception handling to log the exception, and I do the same thing with GEH for non Core WebAPI and doing the logging with Log4net, which means there are no try/catches in the WebAPI(s) or in any code a WebAPI(s) uses. The stack trace on an exception thrown caught by the GEH gives the class name, method name  and like number where the execution is thrown. I just log exception errors in either case of  what WebAPI type is being used.

    Yes, you can do a lot of things with Serilog, like capturing information for debugging, error, informational, statistics, usage and all kinds of logging. I took a Pluralsight course on Serilog. I can tell you now that you don't have Serilog implemented to do it. It may be best that you take the $39 Pluralsight  course on Serilog  if you what to do some logging other than error logging. 

    Thursday, September 20, 2018 1:23 PM
  • User-154169686 posted

    Hi 

    Thanks for reply. I found a solution of using DI and I am using Autofac.

    However, I am still not sure how to get ClassName.Method name everytime I write a error usin serilog.

    Regards,

    Monday, September 24, 2018 6:34 AM
  • User1120430333 posted

    Hi 

    Thanks for reply. I found a solution of using DI and I am using Autofac.

    However, I am still not sure how to get ClassName.Method name everytime I write a error usin serilog.

    Regards,

    Here is how I use Serilog to do global exception handling  in WebAPI Core 2, which means there are no try/catch in any WebAPI code or any DLL code the WebAPI is referencing.

    https://stackify.com/csharp-catch-all-exceptions/

    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Hosting;
    using Serilog;
    
    namespace ProgMgmntCore2Api
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>()
                    .UseSerilog();
        }
    } 
    
    using System.Net;
    using DAL;
    using Entities;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Diagnostics;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Serilog;
    
    namespace ProgMgmntCore2Api
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
                Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                //DAL
                services.AddTransient<IDaoProject, DaoProject>();
                services.AddTransient<IDaoTask, DaoTask>();
                services.AddTransient<IDaoCache, DaoCache>();
    
                //Configuration
                services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
    
                // Add framework services.
                services.AddMvc(options =>
                {
                    options.Filters.Add(new ErrorHandlingFilter(Configuration));
    
                });
    
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory, IApplicationLifetime appLifetime)
            {
                //this is used by Postmon and Global Exception handelling to show exception.
                app.UseExceptionHandler(
                    options =>
                    {
                        options.Run(
                            async context =>
                            {
                                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                                context.Response.ContentType = "text/html";
                                var ex = context.Features.Get<IExceptionHandlerFeature>();
                                if (ex != null)
                                {
                                    var err = $"<h1>Error: {ex.Error.Message} </h1>{ex.Error.StackTrace } {ex.Error.InnerException.Message} ";
                                    await context.Response.WriteAsync(err).ConfigureAwait(false);
                                }
                            });
                    }
                );
    
    
                loggerfactory.AddSerilog();
                app.UseHttpsRedirection();
                app.UseMvc();
    
            }
        }
    }
    
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.Configuration;
    using Serilog;
    
    namespace ProgMgmntCore2Api
    {
        public class ErrorHandlingFilter : ExceptionFilterAttribute
        {
            private readonly IConfiguration _configuration;
    
            public ErrorHandlingFilter(IConfiguration configuration)
            {
                _configuration = configuration;
            }
    
            public override void OnException(ExceptionContext context)
            {
                var log = new LoggerConfiguration().ReadFrom.Configuration(_configuration).CreateLogger();
    
                var exception = context.Exception;
    
                if (exception.InnerException != null)
                {
                    log.Error("Message = " + exception.Message + " Inner.Exception.Message = " +
                              exception.InnerException.Message
                              + " Stack Trace = " + exception.StackTrace);
                }
                else
                {
                    log.Error("Message = " + exception.Message + " Stack Trace = " + exception.StackTrace);
                }
    
                context.ExceptionHandled = false; //optional 
            }
        }
    }
    
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.Configuration;
    using Serilog;
    
    namespace ProgMgmntCore2Api
    {
        public class ErrorHandlingFilter : ExceptionFilterAttribute
        {
            private readonly IConfiguration _configuration;
    
            public ErrorHandlingFilter(IConfiguration configuration)
            {
                _configuration = configuration;
            }
    
            public override void OnException(ExceptionContext context)
            {
                var log = new LoggerConfiguration().ReadFrom.Configuration(_configuration).CreateLogger();
    
                var exception = context.Exception;
    
                if (exception.InnerException != null)
                {
                    log.Error("Message = " + exception.Message + " Inner.Exception.Message = " +
                              exception.InnerException.Message
                              + " Stack Trace = " + exception.StackTrace);
                }
                else
                {
                    log.Error("Message = " + exception.Message + " Stack Trace = " + exception.StackTrace);
                }
    
                context.ExceptionHandled = false; //optional 
            }
        }
    }
    
    2018-08-04 16:10:42.699 -04:00 [Error] An exception was thrown attempting to execute the error handler.
    System.NullReferenceException: Object reference not set to an instance of an object.
       at ProgMgmntCore2Api.Startup.<>c.<<Configure>b__5_1>d.MoveNext() in C:\Projects\ProgMgmntCore2\ProgMgmntCore2Api\Startup.cs:line 62
    --- End of stack trace from previous location where exception was thrown ---
       at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
    2018-08-04 16:10:42.704 -04:00 [Error] Connection id ""0HLFQ8P67SHVQ"", Request id ""0HLFQ8P67SHVQ:00000005"": An unhandled exception was thrown by the application.
    System.Exception: Cache Test
       at DAL.DaoCache.GetCache() in C:\Projects\ProgMgmntCore2\DAL\DaoCache.cs:line 34  at ProgMgmntCore2Api.Controllers.CacheController.Get_Cache() in C:\Projects\ProgMgmntCore2\ProgMgmntCore2Api\Controllers\CacheController.cs:line 24 at lambda_method(Closure , Object , Object[] ) at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ExceptionContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

    Monday, September 24, 2018 7:25 PM