Serilog different levels for different sinks - .net-core

I have the following piece of c# code for writing logs with multiple sinks (console and file), how do i restrict the console to log only (info, warn and error) and file to log everything.
var outputTemplate = "[{Level:u3}] {Message:lj}{NewLine}{Exception}";
// Logger
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Console(outputTemplate: outputTemplate, theme:SystemConsoleTheme.Literate)
.WriteTo.File($"logs/log-{DateTime.Now:yyyy-MM-dd_HH:mm:ss.fff}.log")
.CreateLogger();

You can set a value for restrictedToMinimumLevel for each sink, to raise the minimum level that it should log.
It's explained in the documentation with examples:
https://github.com/serilog/serilog/wiki/Configuration-Basics#overriding-per-sink
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File("log.txt")
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
.CreateLogger();

Related

Serilog not working in ASP.NET Core 7 Integration Test with CustomWebApplicationFactory<Program>

I'm trying to use separate configuration file for Serilog in my Integration Tests in my ASP.NET Core 7 Web API.
Here is my Program.cs,
//Read Configuration from appSettings
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
Log.Information($"Starting {typeof(Program).Assembly.FullName}");
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();//Uses Serilog instead of default .NET Logger
// Removed code for brevity
var app = builder.Build();
// Removed code for brevity
await app.RunAsync();
Here is my CustomWebApplicationFactory<Program>,
public class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
var projectDir = Directory.GetCurrentDirectory();
builder.ConfigureAppConfiguration((context, conf) =>
{
conf.AddJsonFile(Path.Combine(projectDir, "appsettings.Test.json"));
});
builder.UseEnvironment("Test");
builder.ConfigureTestServices(async services =>
{
// Removed code for brevity
});
}
}
As seen in the above code, I have my appsettings.Test.json inside the root of my Integration Test project.
When I run the test, it always takes the appsettings.json from my API project. So I tried to change my Program.cs as follows,
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsEnvironment("Test"))
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.Test.json")
.Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
}
else
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
}
Log.Information($"Starting {typeof(Program).Assembly.FullName}");
builder.Host.UseSerilog();//Uses Serilog instead of default .NET Logger
// Removed code for brevity
var app = builder.Build();
// Removed code for brevity
await app.RunAsync();
After the above change no logs we recorded during my Integration Test. So I decided to add appsettings.Test.json to my API project and Copy Always to output directory but still no luck.
Previously when I was using Startup.cs, I used to override CreateHost inside CustomWebApplicationFactory<Startup> as shown below,
protected override IHostBuilder CreateHostBuilder()
{
//Read Configuration from appSettings
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.Test.json")
.Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
Log.Information($"Starting Integration Tests.");
var builder = Host.CreateDefaultBuilder()
.UseSerilog()
.ConfigureWebHost(x =>
{
x.UseStartup<Startup>();
x.UseTestServer();
});
return builder;
}
But now after moving to new way in ASP.NET Core 7. There is no Startup.cs and the test was giving error like,
No Application was selected to run/start.
So I removed override IHostBuilder CreateHostBuilder() from CustomWebApplicationFactory<Program>.
Please can anyone assist on how to use separate configuration file for Integration Test in ASP.NET Core 7?
I ran into the same issue, as net7 microsoft docs (and Visual Studio 2022 intellisense/warnings) on changing the appSettings config are not aligned with what Serilog requires.
Microsoft's recommendation to change appSettings config (and then setup Serilog, based on Serilog's recommendations):
var builder = WebApplication.CreateBuilder(args);
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
builder.Configuration.Sources.Clear();
builder.Configuration.AddJsonFile("siteid.json", optional: false, reloadOnChange: true);
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Configuration.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true);
builder.Configuration.AddEnvironmentVariables();
if (args != null) builder.Configuration.AddCommandLine(args);
// Configure Serilog
builder.Host.UseSerilog((hostingContext, loggerConfiguration) =>
loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
);
But this results in Serilog not logging anything as you stated.
My solution was to config appSettings using builder.Host.ConfigureAppConfiguration(), as builder.Host is what Serilog seems to use:
#pragma warning disable ASP0013 // Warning suggests switching from using Configure methods to WebApplicationBuilder.Configuration
var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.Sources.Clear();
config.AddJsonFile("siteid.json", optional: false, reloadOnChange: true);
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddEnvironmentVariables();
if (args != null) config.AddCommandLine(args);
});
#pragma warning restore ASP0013
// Configure Serilog
builder.Host.UseSerilog((hostingContext, loggerConfiguration) =>
loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
);
This works and the correct appSettings are populated and Serilog logs as expected. However Visual Studio shows a Warning and suggests switching from using Configure methods (ConfigureAppConfiguration) to WebApplicationBuilder.Configuration (builder.Configuration.AddJsonFile), thus the #pragma warning disable ASP0013 lines.
So in your specific case, I can't offer any guidance in regards to your factory, but on updating your Program.cs, I might suggest this as a soution:
#pragma warning disable ASP0013 // Warning suggests switching from using Configure methods to WebApplicationBuilder.Configuration
var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment; // getting enviroment here instead of your `builder.Environment.IsEnvironment("Test")`
config.Sources.Clear(); // If you want to clear existing defaults ???
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); //(e.g. appsettings.Test.json) overrides any values in appsettings.json
//config.AddEnvironmentVariables();
//if (args != null) config.AddCommandLine(args);
});
#pragma warning restore ASP0013
// Configure Serilog
builder.Host.UseSerilog((hostingContext, loggerConfiguration) =>
loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
);

firebase and spring boot configuration

How to fix that error?
Exception in thread "main" java.io.FileNotFoundException: E:\n\demo%20(1)\demo\target\classes\serviceAccountKey.json (The system cannot find the path specified)
File file = new File(Objects.requireNonNull(classLoader.getResource("serviceAccountKey.json")).getFile());
FirebaseOptions options;
try (FileInputStream serviceAccount = new FileInputStream(file.getAbsolutePath())) {
options = new Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://springboot-c7d7e-default-rtdb.firebaseio.com")
.build();
}

Serilog import log in a class

0 console APP using serilog for logging
using var log = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("myapp.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
Console.WriteLine("Hello, World!");
log.Information("Hello, Serilog!");
Prova p = new Prova();
p.ciao();
I want to use log in a new class Prova. How can i do that without reconfigure serilog?

How to pass connection string to Application Insights?

I have a .NET Core 3.1 console application and would like to configure it using a connection string specified in appsettings.json.
This is the code for a test app:
static void Main(string[] args)
{
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
// To be able to read configuration from .json files
var configuration = configurationBuilder.Build();
// Create the DI container.
IServiceCollection services = new ServiceCollection();
services.AddApplicationInsightsTelemetryWorkerService();
// Build ServiceProvider.
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Obtain TelemetryClient instance from DI, for additional manual tracking or to flush.
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();
telemetryClient.TrackTrace("Hello, world 3!");
// Explicitly call Flush() followed by sleep is required in Console Apps.
// This is to ensure that even if application terminates, telemetry is sent to the back-end.
telemetryClient.Flush();
Task.Delay(5000).Wait();
}
The problem is that it seems like Application Insight is not picking up the connection string. I do not see any Trace messages in Application Insights. If I pass the instrumentation key to AddApplicationInsightsTelemetryWorkerService it works.
This is the content of appsettings.json:
{
"ApplicationInsights": {
"ConnectionString": "<my connection string>"
}
}
What am I missing?
I don't know if the issue is still exist, but you can pass the Connection String straight to the TelemetryConfiguration.
var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
telemetryConfiguration.ConnectionString = Configuration["AzureApplicationInsightsConnectionString"];
Or, you can add it to the servicecollection:
var options = new ApplicationInsightsServiceOptions { ConnectionString = Configuration["AzureApplicationInsightsConnectionString"] };
services.AddApplicationInsightsTelemetry(options: options);

How to get files from Serilog [duplicate]

Hello I am having trouble writing logs to file on Android device using Xamarin.Forms (.NET Core shared project) and Serilog.
So far I have installed Serilog in Shared project. Installed Serilog, Serilog.Sinks.File, and Serilog.Sinks.Xamarin to my Android project and initialized logger in MainActivity:
Log.Logger = new LoggerConfiguration()
.WriteTo.File(Path.Combine(Environment.ExternalStorageDirectory.AbsolutePath,"XamarinLib-{Date}.txt"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}",
fileSizeLimitBytes: 100000000,
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true,
shared: false,
retainedFileCountLimit: 31,
encoding: Encoding.UTF8)
.WriteTo.AndroidLog()
.CreateLogger();
Afterwards I call the logger from shared project like:
Log.Information("Test writing to log file");
I can see the log command being executed in Visual Studio debug output, but the file is simply not created.
I've tried multiple locations on both emulator and actual device (no root access).
I've also tried to use RollingFile sink in similar manner with no success.
Any ideas?
First, you have to allow permissions in your AndroidManifest.xml file.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Next, The user either must, approve that on runtime in which you have to code this in your code behind. NOTE Remember to add Plugin.Permissions on your NUGET package:
InitializeComponent();
Task.Run(async () =>
{
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (status != PermissionStatus.Granted)
{
var accepted = await DisplayAlert("Storage Permission Required",
"Please enable your storage permission, it will be used to store logs and crashes",
"ACCEPT",
"CANCEL");
if(accepted)
{
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Storage);
status = results[Permission.Storage];
}
}
}
catch (Exception ex)
{
await DisplayAlert("Exception ex", "Exception ex", "OK");
}
});
OR
let them change the permissions in the settings -> app -> permissions.
Finally,
change the filename that will link to the storage/emulated/0/[your added directory].
After the closing the app, you can see it in the Android File Manager.
as pointed out by Ruben Bartelink the problem is that Android can't simply write to external storage (ie /storage/emulated/0... etc..).
I was able to log to a file on a Xamarin.Forms project in both Android and iOS.
_Tmp = System.IO.Path.GetTempPath();
_Path = System.IO.Path.Combine(_Tmp, "Serilog.txt");
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File(_Path, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7)
.CreateLogger();
Log.Information("Started new serilogger {SERILOG} on file {FILE}", this, _Path);
Log.CloseAndFlush();
//test
foreach (string log in System.IO.Directory.GetFiles(_Tmp, "*.txt"))
{
string test = System.IO.File.ReadAllText(log);
System.Diagnostics.Debug.WriteLine($"Test[{log}] -> {test}");
}
which printed on the debug console:
[0:] Test[/data/user/0/com.******/cache/Serilog20190819.txt] -> 2019-08-19 16:00:36.997 +02:00 [INF] Started new serilogger ******.Functions.Serilogger on file /data/user/0/com.******/cache/Serilog.txt

Resources