PublishSingleFile, PublishTrimmed and SelfContained .. breaks serilog (Reflection issue?)
My requirements: Have a single executable, as small as possible. Therefor I use the options in the title to bundle everything into one file and turn it from 70+M to 12M (yes, it matters for this).
I need to log information during the runtime of the program and serilog would be my choice. It works fine/as expected in the debugger/while not bundled. I kinda make it work with the single executable now, but it fails to load one sink I need (serilog.sinks.eventlog). When I turn on serilogs own logging, I get the message
2024-01-10T22:55:17.8478998Z Unable to find a method called EventLog for supplied arguments: logName, manageEventSource, source. Candidate methods are:
EventLog(, , , , , , , )
EventLog(, , , , , , )
Going through the code of the project I find https://github.com/serilog/serilog-settings-configuration/blob/dev/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs#L494 which tries to use reflection to
a) find potential matching methods (MethodInfo) - that seems to work, it does find the two "EventLog" extension methods
b) match the method with the arguments provided in serilogs configuration, using the argument names. Seems all argument names are "" though and therefor this fails
I don't believe this is serilog specific and likely more a general problem with bundling and/or trimming, but I have absolutely no idea how I could get to the bottom of this.GitHub
serilog-settings-configuration/src/Serilog.Settings.Configuration/S...
A Serilog configuration provider that reads from Microsoft.Extensions.Configuration - serilog/serilog-settings-configuration
11 Replies
correct, trimming can break code that uses reflection
That's not quite what I'm looking for. Reflection does work here (it finds the methods/MethodInfo instances) and fails to see any (reasonable)
Name
for GetParameters()
- and THAT is rather odd.
Plus, I actually explicitly disabled trimming for that assembly specifically with a custom TrimmingRoots.xml. Something, somewhere, somehow (why??) kills access to the parameter names here it seems.Unknown User•11mo ago
Message Not Public
Sign In & Join Server To View
I'm not using AOT
I did open an issue for Serilog, but I doubt it's on them - I literally talk about MethodInfo.GetParameters().All(p => p.Name == string.Empty) being a weird issue here
Unknown User•11mo ago
Message Not Public
Sign In & Join Server To View
.. I did look at that. It's not related to/doesn't document the issue I'm seeing. I'm reaching out here, hoping that someone knows about weird edge cases. Serilog doesn't explicitly break this and no part of the documentation - your link included - explains what is going on as far as I can tell
I don't trim that file at all though. Unless .. trimming somehow removes/shims the ParameterInfo.Name? 🤔
Let me try to exclude the reflection types from trimming too
Basically I expected trimming to either break stuff (MethodNotFound or something) or work. Here I see something that looks closer to .. symbol stripping of sorts. And those would be in Serilog.Sinks.EventLog, an assembly that I exclude from trimming.
Unknown User•11mo ago
Message Not Public
Sign In & Join Server To View
No, it's not an exception. It's literally working reflection, then LINQ to go through (working, as in .. accessible, reachable) ParameterInfos, then joining their .Name properties (again, working code) as string.Join(", ", ...) .. to get that output. None of that throws. It just doesn't return the parameter names
https://github.com/serilog/serilog-settings-configuration/blob/dev/src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs#L485 this is the code that works with standard reflection types, doesn't throw, has access to methods (the two listed), concats the parameter names (again without throwing, parameter count is correct if I compare it to the methods I want to get here). It's just that the .Name is empty and then lists
EventLog(, , ...)
instead of
EventLog(loggerConfigration, source, logName, ...)
https://github.com/serilog/serilog-sinks-eventlog/blob/master/src/Serilog.Sinks.EventLog/LoggerConfigurationEventLogExtensions.cs#L49
GitHub
serilog-settings-configuration/src/Serilog.Settings.Configuration/S...
A Serilog configuration provider that reads from Microsoft.Extensions.Configuration - serilog/serilog-settings-configuration
GitHub
serilog-sinks-eventlog/src/Serilog.Sinks.EventLog/LoggerConfigurati...
A Serilog sink that writes events to the Windows Event Log - serilog/serilog-sinks-eventlog
See, my confusion is not about things breaking. But how they break makes no sense. There's no exception here, just missing information. Worse, it works with a different sink (I can log to the console for example, which uses the same "I don't support trimming" - but my project excludes that file anyway - serilog.settings.configuration code to do the reflection and matching.
I'm hoping someone here is more familiar with weird and confusing edge cases, hence the question
Solved. Turns out that my
TrimmerRootDescriptor
file wasn't enough, the publishing process still stripped all parameter names from the DLLs (confirmed by extracting and decompiling the published files). Only if I explicitly add TrimmerRootAssembly
¹ entries for the assemblies I care about THEN the information will be retained.
This was quite a painful journey...
â‘ : https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0#root-assembliesTrimming options - .NET
Learn how to control trimming of self-contained apps.