how can I solve error 'The handle is invalid' in serilog - asp.net-core

I have an Asp.net core web api using .net core 6.
I use Serilog to store the app log in a text file.
sometimes I get this error:
Caught exception while emitting to sink Serilog.Sinks.SystemConsole.ConsoleSink: System.IO.IOException: The handle is invalid.
at System.ConsolePal.WindowsConsoleStream.Write(ReadOnlySpan`1 buffer)
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Write(String value)
at System.IO.TextWriter.SyncTextWriter.Write(String value)
at Serilog.Sinks.SystemConsole.ConsoleSink.Emit(LogEvent logEvent)
at Serilog.Core.Sinks.SafeAggregateSink.Emit(LogEvent logEvent)
could you please help me how can I solve this issue?
this is my appsetting:
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.File"
],
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "AppLogs/bckLog-.log",
"rollingInterval": "Day",
"restrictedToMinimumLevel": "Warning"
}
},
{
"Name": "Console"
}
],
"Enrich": [
"FromLogContext"
]
}
and this is my program.cs
Serilog.Debugging.SelfLog.Enable(message => { Log.Logger?.Error(message); Console.WriteLine(message); });
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger();
builder.Host.UseSerilog();

Related

IP Address Not showing up in Serilog

I have setup Serilog with .net 6 asp.net core project but the IP Address is not showing up in the logs using the json formatter.
var logger = new LoggerConfiguration()
.Enrich.WithClientIp()
.Enrich.WithClientAgent()
.Enrich.FromLogContext()
.ReadFrom.Configuration(builder.Configuration)
.CreateLogger();
builder.Logging.ClearProviders();
builder.Logging.AddSerilog(logger);
And I have setup my appsettings like this. But I'm not sure why the IP Address is not showing up in the logs for any request (get, put, etc.)
"Serilog": {
"Using": [ "Serilog.Sinks.File, Serilog.Enrichers.ClientInfo" ],
"MinimumLevel": {
"Default": "Information"
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId", "WithClientIP", "WithClientAgent" ],
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "===> {Timestamp:HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "C://Temp//appLog_.json",
"formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog",
"rollOnFileSizeLimit": true,
"fileSizeLimitBytes": 4194304,
"retainedFileCountLimit": 10,
"rollingInterval": "Day"
}
}
]
},
In Program.cs, I change the code into below code:
builder.Host.UseSerilog((ctx, lc) => lc
.WriteTo.Console()
.ReadFrom.Configuration(ctx.Configuration));
...
app.UseSerilogRequestLogging(options =>
{
// Customize the message template
options.MessageTemplate = "{RemoteIpAddress} {RequestScheme} {RequestHost} {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
// Emit debug-level events instead of the defaults
options.GetLevel = (httpContext, elapsed, ex) => LogEventLevel.Debug;
// Attach additional properties to the request completion event
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
diagnosticContext.Set("RemoteIpAddress", httpContext.Connection.RemoteIpAddress);
};
});
Read net6.0 Serilog example and Adding IP logging to know more.

How to change/override FilePath when creating logger using Serilog

I want to change/override the filename declared appsettings.json with whatever I provide when I setup the logger while keeping all the other settings as is.
I have serilog settings declared in the appsettings.json
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Information",
"System": "Information"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path":"MyAppName_.log"
"rollOnFileSizeLimit": "true",
"fileSizeLimitBytes": 1000000,
"rollingInterval": "Day",
"flushToDiskInterval": 1,
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message:lj}{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext", "%COMPUTERNAME%", "WithThreadId", "USERNAME","USERDOMAIN" ],
"Properties": { "Application": "MyAppName" }
}
The below code is in ConfigureServices method in Startup.cs
var appName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
var fileName = #$"C://Logs/{MyAppName}\{MyAppName}-{DateTime.Today.ToString("MM-dd-yyyy")}.log";
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.WriteTo.File(fileName)
.CreateLogger();
Is it possible?
I am using ASP.NET Core 3.1 and Serilog.AspNetCore 3.2.0

Exception in Serilog Initialization

I'm attempting to try Serilog out in an asp.net core web api (3.1) but seem to be having trouble with the following:
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.log.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
//Configure logger
var loggerConfiguration = new LoggerConfiguration().ReadFrom.Configuration(configuration);
Log.Logger = loggerConfiguration.CreateLogger();
It is throwing the exception:
Exception has occurred: CLR/System.InvalidOperationException
An unhandled exception of type 'System.InvalidOperationException' occurred in Microsoft.Extensions.Configuration.Binder.dll: 'Cannot create instance of type 'System.String' because it is missing a public parameterless constructor.'
at Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(Type type)
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, Object instance, IConfiguration config, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.Get(IConfiguration configuration, Type type, Action`1 configureOptions)
at Microsoft.Extensions.Configuration.ConfigurationBinder.Get(IConfiguration configuration, Type type)
at Serilog.Settings.Configuration.ObjectArgumentValue.ConvertTo(Type toType, ResolutionContext resolutionContext)
at Serilog.Settings.Configuration.ConfigurationReader.<>c__DisplayClass18_2.<CallConfigurationMethods>b__3(<>f__AnonymousType9`2 <>h__TransparentIdentifier0)
at System.Linq.Utilities.<>c__DisplayClass2_0`3.<CombineSelectors>b__0(TSource x)
at System.Linq.Enumerable.SelectListPartitionIterator`2.ToList()
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Serilog.Settings.Configuration.ConfigurationReader.CallConfigurationMethods(ILookup`2 methods, IList`1 configurationMethods, Object receiver)
at Serilog.Settings.Configuration.ConfigurationReader.ApplySinks(LoggerConfiguration loggerConfiguration)
at Serilog.Settings.Configuration.ConfigurationReader.Configure(LoggerConfiguration loggerConfiguration)
at Serilog.Configuration.LoggerSettingsConfiguration.Settings(ILoggerSettings settings)
at Serilog.ConfigurationLoggerConfigurationExtensions.Configuration(LoggerSettingsConfiguration settingConfiguration, IConfiguration configuration, String sectionName, DependencyContext dependencyContext)
at Serilog.ConfigurationLoggerConfigurationExtensions.Configuration(LoggerSettingsConfiguration settingConfiguration, IConfiguration configuration, DependencyContext dependencyContext)
My appsettings.log.json looks like this:
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": "Debug",
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "%ProgramData%\\Logs\\BoxIt\\BoxIt-{Date}.txt",
"rollOnFileSizeLimit": "true",
"rollingInterval": "Day",
"fileSizeLimitBytes": 10000000,
"outputTemplate:": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Destructure": [
{
"Name": "ToMaximumDepth",
"Args": { "maximumDestructuringDepth": 4 }
},
{
"Name": "ToMaximumStringLength",
"Args": { "maximumStringLength": 100 }
},
{
"Name": "ToMaximumCollectionCount",
"Args": { "maximumCollectionCount": 10 }
}
],
"Properties": {
"Application": "Box-It"
}
}
}
Most of the articles I've read initialize this in a very similar fashion so I'm not quite sure if there is something wrong with the config file or how I'm reading the configuration.
"outputTemplate:": was the issue here. The colon inside the double quotes was a mistake and was leading to the error above.

logging with Serilog Concurrently to AzureTableStorage

Logging to AzureTableStorage is causing an overhead that blocks next calls, compared to when logging into a file, is there a way to make this process faster (batch or async option)?
My code in appsetttings.josn:
"Serilog": {
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "AzureTableStorage",
"Args": {
"storageTableName": "tbl",
"connectionString": "DefaultEndpointsProtocol=http;AccountName=xxx;AccountKey=/xxxxxxxx"
}
}
]
}
I ended up using https://github.com/serilog/serilog-sinks-async and the batch option in AzureTableStorage, similar to:
"WriteTo": [
{
"Name": "Async",
"Args": {
"configure": [
{
"Name": "AzureTableStorage",
"Args": {
"storageTableName": "tbl",
"connectionString": "DefaultEndpointsProtocol=http;AccountName=xxx;AccountKey=xxx"
}
}
]
}
}
]

Appending arrays in from appsettings.{Environment}.json to appsettings.json

This is very similar to this question except its about appending arrays between two different JSON files.
I have an ASP.NET Core application
I have the following in appsettings.Development.Json
"Serilog": {
"WriteTo": [
{
"Name": "ApplicationInsightsTraces",
"Args": { "instrumentationKey": "XXXXXXXX" }
}
]
}
And in appsettings.json:
"Serilog": {
// . . . Rest of Serilog configs
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {RequestId}-{SourceContext} {$Scope:lj}: {Message:lj}{NewLine}{Exception}"
},
"restrictedToMinimumLevel": "Information"
},
}
Because Keys overwrite other keys in Appsettings.json I end up with the Console sink being overridden. Is there a syntax to allow it to be appended?
The answer is to use WriteTo:1 and make it an object not an array in appsettings.Development.json like so:
"Serilog": {
"WriteTo:1":
{
"Name": "ApplicationInsightsTraces",
"Args": { "instrumentationKey": "d95066c9-0b17-4e0a-84d4-bb2a4f111016" }
}
}