My day job involves a lot of .NET Core development and a whole lot of logging. As a result, I've become accustomed to having logs when I need them. When working on pet projects I usually don't spend as much time on the "niceties" of life. Lately I've started doing it a little more and wanted to detail some findings.
You could read through those if you want, they mostly say the same things.
"...it’s something I’ve wished for..."
"...really cool package..."
I always end up having to re-google these documents whenever I start a project because I have a hard time remembering the particulars. So I'm going to lay them out here:
public static void Main(string[] args)
await BuildApplication();
private static CommandLineApplication BuildApplication()
var app = new CommandLineApplication();
app.Command("start", config =>
config.HelpOption("--help");
var option = config.Option(
"-o|--option",
"Some fancy option",
CommandOptionType.SingleValue);
var multiOption = config.Option(
"-m|--multi-option",
"Some fancy multi-option",
CommandOptionType.MultipleValue);
var flagOption = config.Option(
"-f|--flag",
"Some fancy flag",
CommandOptionType.NoValue);
var arg1Arg = config.Argument(
"[arg1]",
"Some fancy argument");
var argListArg = config.Argument(
"[argList] ...",
"Some argument list",
multipleValues: true);
config.OnExecute(async () => {
var optionValue = option.HasValue()
? option.Value()
: "Some Default Value";
var multiOptionValue = multiOption.Values;
var isFlag = flagOption.HasValue();
var arg1Value = arg1Arg.HasValue()
? arg1Arg.Value()
: "Some Default Value";
var argListValue = argListArg.Values;
// TODO : Something
app.Execute(args);
Serilog
We use
Serilog
for logging instead of the vanilla Microsoft.Extensions.Logging. It adds a few more bells and whistles to your logs and has worked really well for us. The drawback with Serilog is that certain things (ie. setup) is challenging to get working. Below are some of those steps in copy/pasta form.
We use a JSON appsettings file for work but I much prefer YAML.
Dependencies
Serilog
Serilog.Settings.Configuration
Microsoft.Extensions.Configuration.Yaml
Copy/Pasta Starter
public static void Main(string[] args)
var configuration = BuildConfiguration();
var logger = BuildLogger(configuration);
public static IConfiguration BuildConfiguration()
return new ConfigurationBuilder()
.AddYamlFile("appsettings.yaml")
.Build();
public static ILogger BuildLogger(IConfiguration config)
return new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
The
actual
challenging part using Serilog is with a configuration file. The documentation for interacting with Serilog via Serilog.Settings.Configuration is incredibly sparse. The trick is figuring out how to pass arguments generally passed when programmatically configuring the logger.
The simplest way to explain this is to show the extension methods for setting up the Console sink programmatically and then showing what that turns into in the configuration file:
As you can see,
Console
extends
LoggerSinkConfiguration
and accepts a bunch of parameters - most of which are defaulted. When you specify Serilog.Sinks.Console in
appsettings.yaml
, the configuration reader is actually locating one of these methods and calling it on an internal configuration builder.
So how de we pass parameters to this? The following shows how to pass in a
IFormatProvider
to the Console extension method. The formatter is one I'm using for
Guid
s and is merely used as an example.
The takeaway here is that the arguments are passed in as an key/value dictionary to
Args
.
Tying it all together with Dependency Injection
DI is great and can really simplify your code and object activation and management. Microsoft provides
Microsoft.Extensions.DependencyInjection
and it gets the job done.