andyopayne
andyopayne

Reputation: 1368

Serilog send different output based on context

I'm using Serilog to log information on my app. I'm using an appsettings.json file (see below) to setup the configuration settings of the logger. In that file, I have two configurations - one for writing to a file and another for writing to the console output. What I would like to be able to do is to only write to a file if my application is running in the IIS context. Otherwise, it should only output the log to the console. However, I'm a bit stuck on how to do this.

appsettings.json

{
    "Serilog": {
        "Using": [ "SeriLog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Async" ],
        "MinimumLevel": {
            "Default": "Information",
            "Override": {
                "Microsoft": "Information",
                "Microsoft.AspNetCore": "Warning",
                "System": "Warning"
            }
        },
        "WriteTo": [
            {
                "Name": "File",
                "Args": {
                    "outputTemplate": "RC  [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}",
                    "path": "logs/mylog-.txt",
                    "rollingInterval": "Day"
                }
            },
            {
                "Name": "Console",
                "Args": {
                    "outputTemplate": "RC  [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
                }
            }
        ],
        "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
        "Properties": {
            "Application": "MyApplication"
        }
    },
    "AllowedHosts": "*"
}

Program.cs

public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables()
    .Build();

public static void Main(string[] args)
{
    Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
    Config.Load();
    Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(Configuration)
    .Filter.ByExcluding("RequestPath in ['/healthcheck', '/favicon.ico']")
    .CreateLogger();

    var host = Host.CreateDefaultBuilder(args)
        .UseSerilog()
        .ConfigureWebHostDefaults(webBuilder =>
        {
            var b = webBuilder.ConfigureKestrel((context, options) =>
            {
                // Handle requests up to 50 MB
                options.Limits.MaxRequestBodySize = Config.MaxRequestSize;
            })
            .UseIISIntegration()
            .UseStartup<Startup>()
            .CaptureStartupErrors(true);
        }).Build();

    var logger = host.Services.GetRequiredService<ILogger<ReverseProxyModule>>();
    ReverseProxyModule.InitializeConcurrentRequestLogging(logger);

    host.Run();
}

Upvotes: 0

Views: 58

Answers (2)

Jalpa Panchal
Jalpa Panchal

Reputation: 12789

You could also try to use the is below code in the program.cs file to generate file logs for the iis environment only.

using Serilog;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;

var builder = WebApplication.CreateBuilder(args);

// Load configuration
var configuration = builder.Configuration;

//  Detect if running under IIS or Azure App Service
bool isRunningUnderIIS = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH") != null
    || Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID") != null; // Azure App Service support

// Debugging logs
Console.WriteLine($"Environment: {builder.Environment.EnvironmentName}");
Console.WriteLine($"ASPNETCORE_IIS_HTTPAUTH: {Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH")}");
Console.WriteLine($"WEBSITE_INSTANCE_ID: {Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID")}");
Console.WriteLine($"Is running under IIS: {isRunningUnderIIS}");

//  Configure Serilog dynamically and IGNORE `appsettings.json` for logging sinks
var loggerConfig = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .Enrich.WithMachineName()
    .Enrich.WithThreadId();

if (isRunningUnderIIS)
{
    Console.WriteLine(" Running under IIS, enabling File logging...");
    loggerConfig.WriteTo.File("logs/mylog-.txt", rollingInterval: RollingInterval.Day,
        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}");
}
else
{
    Console.WriteLine(" Running Locally, enabling Console logging...");
    loggerConfig.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}");
}

//  Apply Serilog
Log.Logger = loggerConfig.CreateLogger();
builder.Host.UseSerilog();

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build(); 

// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment() || app.Environment.IsProduction())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseSerilogRequestLogging();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Result from visual studio:

enter image description here

Result after deploying on iis: enter image description here

Upvotes: 0

Super user
Super user

Reputation: 1

If you mean one sink for when it is live in production and one for when developing on your local computer, you could have an appsettings.production.json and an appsettings.development.json, and keep the appsettings.json for configurations that should apply to both.

Upvotes: 0

Related Questions