In Asp.net Core version 3.1 I have tried to log LogInformation to Application Insights, but it is not logging in App Insight.
private readonly ILogger<LogService> _logger;
public LogService(IOptions<LogConfig> logConfig, ILogger<LogService> logger)
{
_logConfig = logConfig.Value;
_logger = logger;
}
_logger.LogInformation("Parameters: {Log Info}", _logConfig.IsLogEnabled);
But Logging Error is working
_logger.LogError(e, "Parameters: {HttpMethod}, {ErrorCode}", logEntry.HttpMethod, logEntry.ErrorCode);
Using package Microsoft.ApplicationInsights.AspNetCore version 2.21.0
In Startup.cs
services.AddApplicationInsightsTelemetry();
In appSettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
},
"ConnectionString": "secret"
}
}
You are setting the AI loglevel at the incorrect level. It should be like this:
{
"Logging": {
"LogLevel": {
"Default": "Information"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
},
"ApplicationInsights": {
"ConnectionString": "secret"
}
}
Related
I need to be able to switch between Serilog and another logger, MyLog. Currently I am switching by comment/uncomment code as the following:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
//// === to switch between Serilog and MyLogger comment/uncomment code below ===
//.UseSerilog((hostContext, loggerConfig) =>
// loggerConfig.ReadFrom.Configuration(hostContext.Configuration));
.ConfigureLogging((hostBuilderContext, logging) =>
{
logging.AddMyLogger(options =>
{
hostBuilderContext.Configuration.GetSection(MyLoggerOptions.LogOptions).Bind(options);
});
});
}
This works, but I prefer to make it controlled by a appsettings.json setting, say, Logger. So here is my appsettings.json file:
{
"Logger": "Serilog", // Use Serilog or MyLog
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
},
"MyLog": {
"Options": {
"FolderPath": "logs",
"FilePath": "Svr_{date}.log"
},
"LogLevel": {
"Default": "Information",
"Microsoft": "Error",
"Microsoft.Hosting.Lifetime": "Error"
}
}
},
"Serilog": {
"MinimumLevel": "Verbose",
"Override": {
"Microsoft.AspNetCore": "Warning"
},
"WriteTo": [
{
"Name": "Console "
},
{
"Name": "File",
"Args": {
"path": "Logs\\Serilog_Server-.log",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
"rollingInterval": "Day"
}
}
]
}
}
and here is the code where I try to set log depending on the Loger setting:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging((hostBuilderContext, logging) =>
{
string loger = hostBuilderContext.Configuration.GetValue<String>("Logger");
if (loger == "MyLog")
{
logging.AddMyLogger(options =>
{
hostBuilderContext.Configuration.GetSection(MyLoggerOptions.LogOptions).Bind(options);
});
}
else if (loger == "Serilog")
{
logging.AddSerilog(); // here is the problem. Serilog doesn't write.
}
});
The problem of this code is the Serilog (MyLog is fine) - it doesn't write at all. My guess is that, since I don't have a way to pass in the configuration object, it might not get configured properly. But how do I fix it? or is there a better way to do this?
UPDATE
Tried what Camilo suggested as the following with an error. How do I get the configuration object from here?
ILogger is not injected when using new DI functionality and not showing the log information in the console.
public class SampleGreeter : IGreeter
{
private readonly ILogger<SampleGreeter> logger;
public SampleGreeter(ILogger<SampleGreeter> logger)
{
this.logger = logger;
}
public string CreateGreeting(string name)
{
logger.LogInformation("Logging from greeter");
return $"Hello, {name}. I'm a sample greeter.";
}
}
Nothing is logged from greeter, while logging from function runtime works and is showing in the console.
host.json file:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"fileLoggingMode": "debugOnly",
"logLevel": {
"default": "Information",
"<namespace>": "Information"
},
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}
}
Microsoft documentation says:
"The host injects ILogger and ILoggerFactory services into constructors. However, by default these new logging filters are filtered out of the function logs. You need to modify the host.json file to opt-in to additional filters and categories."
Microsoft documentation and example
You've put
"logLevel": {
"default": "Information",
"<namespace>": "Information"
},
(and fileLoggingMode) within the applicationInsights level, but that's not the right one: it should be one level higher, as in the sample configuration file:
"logging": {
"fileLoggingMode": "debugOnly",
"logLevel": {
"default": "Information",
"<namespace>": "Information"
},
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}
I'm initializing Serilog in Program.cs, reading the configuration from appsettings.json, adding middleware in Startup.cs -> Configure and Use Request Middleware. Some snippets:
Starup Extension
public static void UseSerilogRequestMiddleware(this IApplicationBuilder app)
{
app.UseMiddleware<RequestMiddleware>();
app.UseSerilogRequestLogging();
}
Create Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.Enrich.FromLogContext()
.WriteTo.UDPSink(configuration["Serilog:LogstashUrl"], int.Parse(configuration["Serilog:LogstashPort"]), new JsonFormatter())
.CreateLogger();
Middleware
public async Task InvokeAsync(HttpContext httpContext)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
try
{
using (LogContext.PushProperty("CorrelationId", httpContext.GetCorrelationId()))
using (LogContext.PushProperty("UserName", httpContext.Request.Headers["UserName"]))
using (LogContext.PushProperty("Path", httpContext.Request.Path))
using (LogContext.PushProperty("QueryString", httpContext.Request.Query))
{
await _next(httpContext).ConfigureAwait(false);
}
}
catch (Exception ex)
{
await HandleExceptionAsync(httpContext, ex).ConfigureAwait(false);
}
}
appSettings
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"WriteTo": [ { "Name": "Console" } ],
"Enrich": [ "FromLogContext", "WithMachineName", "WithExceptionDetails" ],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "RequestPath like '/health%'"
}
},
{
"Name": "ByExcluding",
"Args": {
"expression": "RequestPath like '/swagger%'"
}
}
],
"LogstashUrl": "logstash-teste-log",
"LogstashPort": "5045"
}
In the middleware I want to push some properties to the logs. When I configure Serilog as written above the properties are not visible in the logs
I am using ASP.NET Core 2.0. Below is my code.
Startup:
namespace foo
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
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)
{
// Add framework services.
services
.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddDbContext<fooContext>(options => options.UseSqlServer(Configuration.GetConnectionString("UserDatabase")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
appsettings.json:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"ConnectionStrings": {
"UserDatabase": "Server=DESKTOP-FSES7UK;Database=xxx;User Id=sa; Password=xxxxxxx;Trusted_Connection=True;"
}
}
}
How to fix it?
As mentioned in the comment, try to move your connection string to the top (suggestion) fix is to take the key *"ConnectionStrings" *outside of logging key
appsettings.json
{
"ConnectionStrings": {
"UserDatabase": "Server=DESKTOP-FSES7UK;Database=xxx;User Id=sa; Password=xxxxxxx;Trusted_Connection=True;"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
Problem is your ConnectionStrings object has been a property of Logging object. Write your appsettings.json as follows:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
},
"ConnectionStrings": {
"UserDatabase": "Server=DESKTOP-FSES7UK;Database=xxx;User Id=sa; Password=xxxxxxx;Trusted_Connection=True;"
}
}
I'm having trouble getting the logger to work like i want it to. I've set the loglevel to warning, but the console window is still bloated with info logs.
I've provided some examples below, nothing extra is configured in Startup.cs or Program.cs.
I'm happy to provide more information if needed.
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "ConnectionString"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning"
}
}
}
Logging example:
public class DishRepository : IDishRepository
{
private readonly ApplicationDbContext _context;
private readonly ILogger<DishRepository> _logger;
public DishRepository(ApplicationDbContext context, ILogger<DishRepository> logger)
{
_context = context;
_logger = logger;
}
public IEnumerable<Dish> GetAll()
{
try
{
_logger.LogInformation("GetAll was called");
return _context.Dishes
.Include(d => d.Category)
.Include(d => d.DishIngredients)
.ThenInclude(di => di.Ingredient)
.Include(d => d.PizzaType).ToList();
}
catch (Exception e)
{
_logger.LogError($"Failed to get all dishes: {e}");
return Enumerable.Empty<Dish>();
}
}
}
When i run my program via VisualStudio i get this:
--------This Works--------
I found the example below at https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?tabs=aspnetcore2x it works, but I don't understand why this works and not the appsettings.json example above.
appsettings.json
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"PizzeriaAngular": "Warning",
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
Program.cs still looks like this:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
There are two config files appsettings.json and appsettings.Development.json. And system use it in development mode.
This code work for me (NetCore 2.x)
in class Startup.cs in method ConfigureServices(IServiceCollection services)
services.AddLogging(builder =>
{
builder.SetMinimumLevel(LogLevel.Trace);
builder.AddFilter("Microsoft", LogLevel.Warning);
builder.AddFilter("System", LogLevel.Error);
builder.AddFilter("Engine", LogLevel.Warning);
});
If you are using another logging provider, like NLog, then the "Logging" appsettings for Microsoft will not work.
For NLog, you have to set the minimum logging level in the nlog.config:
<logger name="*" minlevel="Info" writeTo="default" />