<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Karl Stålenheim</title><link href="http://world.optimizely.com" /><updated>2025-11-12T12:42:53.0000000Z</updated><id>https://world.optimizely.com/blogs/karl-stalenheim/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Using Serilog in DXP</title><link href="https://world.optimizely.com/blogs/karl-stalenheim/dates/2025/11/using-serilog-in-optimizely-dxp/" /><id>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&amp;nbsp;Use &lt;em&gt;Serilog.Sinks.Console&lt;/em&gt; for DXP apps &amp;mdash; or skip Serilog entirely and rely on default logging.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;It&amp;rsquo;s common during investigations that all the downloadable logs from the PaaS portal are empty.&lt;/p&gt;
&lt;p&gt;In most cases, this happens because Serilog is used and configured to only write logs to files. While that works locally or in traditional hosting environments, it doesn&amp;rsquo;t play well with how Optimizely DXP handles logs.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s important to understand (maybe not clearly defined in &lt;a href=&quot;https://docs.developers.optimizely.com/digital-experience-platform/docs/logging&quot;&gt;documentation&lt;/a&gt;) is that the logs available in the PaaS Portal are&amp;nbsp;&lt;strong&gt;App Service Console Logs&lt;/strong&gt; and not file-based logs.&lt;/p&gt;
&lt;h2&gt;Implementing Serilog for Both Development and DXP&lt;/h2&gt;
&lt;p&gt;Below is an example of how the&amp;nbsp;&lt;em&gt;Program &lt;/em&gt;class can look. It uses a &lt;a href=&quot;https://github.com/serilog/serilog-aspnetcore?tab=readme-ov-file#two-stage-initialization&quot;&gt;&lt;strong&gt;bootstrap logger&lt;/strong&gt;&lt;/a&gt; during startup which ensures that logging is available even before the host is fully built, while still letting Serilog load its settings from configuration later on.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Override(&quot;Microsoft&quot;, LogEventLevel.Information)
            .WriteTo.Console()
            .CreateBootstrapLogger();


        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =&amp;gt;
        Host.CreateDefaultBuilder(args)
            .ConfigureCmsDefaults()
            .UseSerilog((context, services, configuration) =&amp;gt;
            {
                configuration
                    .ReadFrom.Configuration(context.Configuration)
                    .ReadFrom.Services(services)
                    .Enrich.FromLogContext();
            })
            .ConfigureWebHostDefaults(webBuilder =&amp;gt;
            {
                webBuilder.UseStartup&amp;lt;Startup&amp;gt;();
            });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup requires the NuGet packages &lt;em&gt;Serilog&lt;/em&gt;, &lt;em&gt;Serilog.AspNetCore&lt;/em&gt; and &lt;em&gt;Serilog.Sinks.Console&lt;/em&gt; are installed.&lt;/p&gt;
&lt;h3&gt;Configuration for Development&lt;/h3&gt;
&lt;p&gt;In development, you might want to see logs both in the console and written to a local file for troubleshooting.&lt;/p&gt;
&lt;p&gt;Your &lt;em&gt;appsettings.Development.json&lt;/em&gt; could look like this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
  &quot;Serilog&quot;: {
    &quot;Using&quot;: [&quot;Serilog.Sinks.Console&quot;, &quot;Serilog.Sinks.File&quot;],
    &quot;MinimumLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Override&quot;: {
        &quot;Microsoft&quot;: &quot;Warning&quot;,
        &quot;EPiServer&quot;: &quot;Information&quot;,
        &quot;EPiServer.Commerce&quot;: &quot;Warning&quot;,
        &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Warning&quot;,
        &quot;MySite.SomeNamespace&quot;: &quot;Information&quot;
      }
    },
    &quot;WriteTo&quot;: [
      { &quot;Name&quot;: &quot;Console&quot; },
      {
        &quot;Name&quot;: &quot;File&quot;,
        &quot;Args&quot;: {
          &quot;path&quot;: &quot;app_data/log.txt&quot;,
          &quot;rollingInterval&quot;: &quot;Day&quot;,
          &quot;retainedFileCountLimit&quot;: 10
        }
      }
    ]
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration assumes the package &lt;em&gt;Serilog.Sinks.File&lt;/em&gt; is installed.&lt;/p&gt;
&lt;h3&gt;Configuration for DXP&lt;/h3&gt;
&lt;p&gt;Logs written to the &lt;strong&gt;console&lt;/strong&gt; are captured as &lt;strong&gt;App Service Console Logs&lt;/strong&gt;. These are the logs visible in the DXP portal.&lt;/p&gt;
&lt;p&gt;For DXP, you can simplify and optimize Serilog by only using the console sink, optionally wrapped in an async sink which may or may not improve performance. This is how &lt;em&gt;appsettings.&amp;lt;ENV&amp;gt;.json&lt;/em&gt; could look like:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
  &quot;Serilog&quot;: {
    &quot;Using&quot;: [&quot;Serilog.Sinks.Async&quot;, &quot;Serilog.Sinks.Console&quot;],
    &quot;MinimumLevel&quot;: {
      &quot;Default&quot;: &quot;Warning&quot;,
      &quot;Override&quot;: {
        &quot;Microsoft&quot;: &quot;Warning&quot;,
        &quot;EPiServer&quot;: &quot;Warning&quot;,
        &quot;EPiServer.Commerce&quot;: &quot;Warning&quot;,
        &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Information&quot;,
        &quot;MySite.SomeNamespace&quot;: &quot;Information&quot;
      }
    },
    &quot;WriteTo&quot;: [
      {
        &quot;Name&quot;: &quot;Async&quot;,
        &quot;Args&quot;: {
          &quot;configure&quot;: [
            { &quot;Name&quot;: &quot;Console&quot; }
          ]
        }
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The configuration assumes that &lt;em&gt;Serilog.Sinks.Async&lt;/em&gt; and &lt;em&gt;Serilog.Sinks.Console &lt;/em&gt;are installed.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;With this setup, you can enjoy all the benefits of Serilog&amp;rsquo;s structured logging while ensuring that logs are still captured correctly in Optimizely DXP.&lt;/p&gt;</id><updated>2025-11-12T12:42:53.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>