0

I have a .net framework application and a library that sets up Serilog. Here is the structure:

Edit:

Code in github

enter image description here

program.cs

using Serilog;
using System;
using Library;
    
namespace SerilogTest
{
    class Program
    {
        private static readonly ILogger Logger = Log.ForContext(typeof(Program));

        static void Main(string[] args)
        {
            LoggerInstaller.Install();

            Logger.Information("It works!");

            Console.ReadLine();
        }
    }
}

LoggInstaller.cs

using Serilog;


namespace Library
{
    static public class LoggerInstaller
    {
        static public Serilog.Core.Logger Install()
        {
            //SelfLog.Enable(Console.Error);

            string logFileName = "MyLog.log";

            var config = new LoggerConfiguration()
                                .ReadFrom.AppSettings()
                                .WriteTo.File(logFileName, rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true, fileSizeLimitBytes: 50000)
                                .CreateLogger();

            Log.Logger = config;

            return config;
        }

    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key="serilog:minimum-level" value="Verbose" />
        <add key="serilog:using:Console" value="Serilog.Sinks.Console" />
        <add key="serilog:write-to:Console" />

        <add key="serilog:write-to:Console.outputTemplate" value="{Timestamp:HH:mm:ss} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}" />

        <add key="serilog:using:Seq" value="Serilog.Sinks.Seq" />
        <add key="serilog:write-to:Seq.serverUrl" value="http://localhost:5341" />

        <add key="serilog:using:File" value="Serilog.Sinks.File" />

        <add key="serilog:using:Thread" value="Serilog.Enrichers.Thread" />
        <add key="serilog:enrich:WithThreadId" />

        <add key="serilog:enrich:FromLogContext" />

        <add key="serilog:using:Environment" value="Serilog.Enrichers.Environment" />
        <add key="serilog:enrich:WithMachineName" />

        <add key="serilog:using:Process" value="Serilog.Enrichers.Process" />
        <add key="serilog:enrich:WithProcessId" />

        <add key="serilog:using:Memory" value="Serilog.Enrichers.Memory" />
        <add key="serilog:enrich:WithMemoryUsage" />

        <add key="serilog:using:AssemblyName" value="Serilog.Enrichers.AssemblyName" />
        <add key="serilog:enrich:WithAssemblyName" />
        <add key="serilog:enrich:WithAssemblyVersion" />

        <add key="serilog:enrich:with-property:Application" value="SerilogTest" />
    </appSettings>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
</configuration>

When I run this code I get the following exception in the library

System.IO.FileNotFoundException: 'Could not load file or assembly 'Serilog.Sinks.Console' or one of its dependencies. The system cannot find the file specified.'

enter image description here

I have to include all the extra Serilog libraries in the SerilogTest app to get it to work. Why is this needed? Why is it not enough to have them in the library?

Q-bertsuit
  • 3,223
  • 6
  • 30
  • 55
  • 2
    Try with the new csproj sdk-style. – vernou Jan 15 '21 at 14:03
  • I haven't heard about that before? – Q-bertsuit Jan 15 '21 at 14:04
  • @Q-bertsuit Link to docs on the new csproj SDK style that vernou suggested - https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview – C. Augusto Proiete Jan 15 '21 at 14:11
  • I'm on .net framework 4.7.2. I can't migrate .net core unfortunately – Q-bertsuit Jan 15 '21 at 14:12
  • New sdk-style is compatible with .NET Framework, just it don't exist template. You need create .NET Standard project and edit the csproj to replace `netstandard2.0` by `net472`. – vernou Jan 15 '21 at 14:20
  • I tried creating a .net standard library, changing it to net472, and adding all the libraries. I'm still getting the same exception – Q-bertsuit Jan 15 '21 at 14:31
  • `` is in the .csproj file – Q-bertsuit Jan 15 '21 at 14:32
  • Can you check if `Serilog.Sinks.Console` is in build result (in `bin` folder)? – vernou Jan 15 '21 at 15:04
  • would be more useful if you post proj file content, not image – T.S. Jan 15 '21 at 16:27
  • add [bindredirect](https://stackoverflow.com/questions/43365736/assembly-binding-redirect-how-and-why) for `Serilog.Sinks.Console` on `app.config` file, did it help? – Mr Qian Jan 18 '21 at 02:56
  • @Vernou It's only in the library bin folder, not the consoles bin folder – Q-bertsuit Jan 18 '21 at 07:17
  • @PerryQian-MSFT I couldn't get it to work unfortunately – Q-bertsuit Jan 18 '21 at 07:27
  • I put the code in guthub https://github.com/q-bertsuit/SerilogTest – Q-bertsuit Jan 18 '21 at 07:27
  • @Q-bertsuit there's no point in uploading anything to GitHub. Post it *in the question itself*. The quickest solution would be to add the NuGet packages you want to your executable. Neither app.config nor binding redirects are going to load a non-existent dll. Besides, it's the *executable* that sets up logging, not the libraries. The libraries should only need to know about the core ILogger interface. – Panagiotis Kanavos Jan 18 '21 at 07:35
  • @Q-bertsuit as for `I can't migrate .net core unfortunately` you don't have much choice - .NET 5 is .NET *Core* 5. .NET Old is essentially legacy at this point, receiving only security updates. You'll have to upgrade sooner or later. You can already create WinForms, WPF and service applications in .NET 5 – Panagiotis Kanavos Jan 18 '21 at 07:40
  • @Q-bertsuit what you called `LoggerInstaller` should be a single `ConfigureLogging` method in `Program.cs`, or a `Startup` class. It's no coincidence that .NET Core uses a Startup class to hold such methods – Panagiotis Kanavos Jan 18 '21 at 07:42
  • I am aware that I will have to upgrade to .Net Core eventually, but for several reasons I can't do it today, so I'm stuck with .Net framework. – Q-bertsuit Jan 18 '21 at 07:46
  • @PanagiotisKanavos If i put the code for LoggerInstaller in program.cs I will have code duplication inn all of my applications, that was the hole motivation for putting it in a library – Q-bertsuit Jan 18 '21 at 07:48
  • @PanagiotisKanavos I guess what you are saying is that what I am trying to do is not possible? I will have to include all 10+ serilog libraries and the code for setting it up inn all my applications? – Q-bertsuit Jan 18 '21 at 07:51
  • That's a LOT easier to do with .NET Core. In .NET Old, indirect requirements have to be added explicilty. Otherwise you'd be able to add just `Serilog.Sinks.Console` and get `Serilog` as well. In .NET Old, you *have* to add indirect dependencies as well – Panagiotis Kanavos Jan 18 '21 at 07:54
  • Yet another argument for me to give my boss that we should prioritize moving to .Net Core soon :-) For now I don't have much choice though.. – Q-bertsuit Jan 18 '21 at 07:56
  • @PanagiotisKanavos ` indirect requirements have to be added explicilty` This means adding a package using nuget right? – Q-bertsuit Jan 18 '21 at 07:57
  • @Q-bertsuit as for pulling all logging configuration to a single library, no application will have the *same* configuration. Maybe they'll need different log file names, different categories, or different sinks. Maybe you'll want to log errors and verbose messages to separate files. Maybe you want to add centralized logging, eg to a database, at some point. Add more sinks. At some point it will be easier to either configure in code, or put everything in the settings file – Panagiotis Kanavos Jan 18 '21 at 07:57
  • @Q-bertsuit why put `WriteTo.File` in code for example? Why not put even that in the settings file? – Panagiotis Kanavos Jan 18 '21 at 07:58
  • But I DO wan't everything in an app.config file! And that file we be different for many of the applications. I was just looking for a way not not have to duplicate the LoggerInstaller code and having so many extra nuget packages in every project. – Q-bertsuit Jan 18 '21 at 07:59
  • @Because I wan't to construct the loggfiles path from code (in base folder of the solution ) – Q-bertsuit Jan 18 '21 at 08:01
  • If it was a fixed relative path I would have put it in app.config as well – Q-bertsuit Jan 18 '21 at 08:02
  • Your requirements contradict each other, and the code you want to avoid duplicating 4 lines. As for the file path, that's one of the reasons creating a single log configuration is hard. Each application will have different requirements – Panagiotis Kanavos Jan 18 '21 at 08:11
  • 1
    As for not having so many extra packages, that's the main difference between .NET Core and .NET Old. In .NET Old, to get the same behavior you'd have to create your own NuGet package that adds all other dependencies and the logging configuration. This means creating a NuSpec file to the library that explicitly references the other packages and add the generated NuGet to your executable, not the project reference – Panagiotis Kanavos Jan 18 '21 at 08:12
  • Why can't you move to .NET Core for a new application? You can even package the entire solution into a single executable, so a missing runtime is no concern – Panagiotis Kanavos Jan 18 '21 at 08:13
  • Just to be clear, I completely agree that a single log configuration is hard. That has never been the point. It's actually quite a bit more than 4 lines of code, I've left out code for simplicity. – Q-bertsuit Jan 18 '21 at 08:30
  • I'm not creating a new application, I'm replacing log4net with Serilog and Seq in a solution with hundreds of existing projects. All .Net framework – Q-bertsuit Jan 18 '21 at 08:31
  • If the answer is that you can't put the configuration in a separate settings file per application, and then put the setup code and all required packages in a separate library, than I'm happy with that answer. I was just looking for a why to not have to include the packages so many times all over the solution. But looks like there is no way around that. Thanks for your help! Really appreciate it – Q-bertsuit Jan 18 '21 at 08:34

0 Answers0