Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[coverlet] Unable to instrument module - NET 5 - Microsoft.Extensions.Logging.Abstractions #1231

Closed
304NotModified opened this issue Oct 2, 2021 · 17 comments
Labels
needs repro Needs repro to be investigated, cannot repro in local

Comments

@304NotModified
Copy link
Contributor

304NotModified commented Oct 2, 2021

For some test projects, but not all, we get

/home/AzDevOps/.nuget/packages/coverlet.msbuild/3.1.0/build/coverlet.msbuild.targets(39,5): warning : [coverlet] Unable to instrument module: MyApi.dll because : AssemblyResolutionException for 'Microsoft.Extensions.Logging.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Try to add to test projects or pass '/p:CopyLocalLockFileAssemblies=' option to the 'dotnet test' command-line

Tried:

  • Adding <PreserveCompilationContext>true</PreserveCompilationContext> to csprojs
  • Also pass /p:CopyLocalLockFileAssemblies=true to dotnet test
  • Included a package reference to Microsoft.Extensions.Logging.Abstractions directly in the test projects.
  • upgrade coverlet from 3.0.3 to 3.1.0

Related:

PS I hope this helps to diagnose the issue #1196. I have run more than 10 builds (with 10 tries), but all have the same issue :(

@304NotModified
Copy link
Contributor Author

304NotModified commented Oct 2, 2021

I fixed this on Azure Devops (Linux build) with a copy of the dll as follows:

This fixes two warnings:

/home/AzDevOps/.nuget/packages/coverlet.msbuild/3.1.0/build/coverlet.msbuild.targets(39,5):
 warning : [coverlet] Unable to instrument module: 
/agent/_work/1/s/Backend/MyApp.Domain.Tests/bin/Release/net5.0/MyApp.Infra.dll 
because : AssemblyResolutionException for 'Microsoft.Extensions.Logging.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. 
Try to add <PreserveCompilationContext>***</PreserveCompilationContext> to test projects </PropertyGroup> or pass '/p:CopyLocalLockFileAssemblies=***' option to the 'dotnet test' command-line 
[/agent/_work/1/s/Backend/MyApp.Domain.Tests/MyApp.Domain.Tests.csproj]

/home/AzDevOps/.nuget/packages/coverlet.msbuild/3.1.0/build/coverlet.msbuild.targets(39,5): 
warning : [coverlet] Unable to instrument module: 
/agent/_work/1/s/Backend/MyApp.Infra.Tests/bin/Release/net5.0/MyApp.Infra.dll 
because: AssemblyResolutionException for 'Microsoft.Extensions.Logging.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. 
Try to add <PreserveCompilationContext>***</PreserveCompilationContext> to test projects </PropertyGroup> or pass '/p:CopyLocalLockFileAssemblies=***' option to the 'dotnet test' command-line 
[/agent/_work/1/s/Backend/MyApp.Infra.Tests/MyApp.Infra.Tests.csproj]

Temp fix:

  - task: PowerShell@2
    displayName: 'fix - [coverlet] Unable to instrument module - Microsoft.Extensions.Logging.Abstractions'
    inputs:
      pwsh: true
      targetType: 'inline'
      script: |
        $dllToFix = "Microsoft.Extensions.Logging.Abstractions.dll"
        $from = "Backend/MyApp.Infra.Tests/bin/Release/net5.0/refs/$dllToFix"
        Copy-Item $from -Destination "Backend/MyApp.Domain.Tests/bin/Release/net5.0"
        Copy-Item $from -Destination "Backend/MyApp.Infra.Tests/bin/Release/net5.0"

it seems I have to copy the dll also one level up? (from .../net5.0/refs to .../net5.0) - does that makes any sense?

update, tested, and I really need to copy from net5.0/refs to the net5.0 folder

@MarcoRossignoli MarcoRossignoli added the untriaged To be investigated label Oct 6, 2021
@MarcoRossignoli
Copy link
Collaborator

Hi @304NotModified thanks for reporting this. We'll take a look asap.

@MarcoRossignoli
Copy link
Collaborator

MarcoRossignoli commented Oct 28, 2021

@304NotModified are you able to provide a repro?I have an idea of the possible problem but I need a repro to validate it.
Is it a desktop app?

@MarcoRossignoli MarcoRossignoli added needs repro Needs repro to be investigated, cannot repro in local and removed untriaged To be investigated labels Oct 28, 2021
@304NotModified
Copy link
Contributor Author

304NotModified commented Oct 28, 2021

It's a ASP.NET Core 5 application with multiple projects.

I'm afraid it will take some time to create a repro.

@hedasilv
Copy link

hedasilv commented Nov 4, 2021

I am having the same issue:

/xxx/xxx/.nuget/packages/coverlet.msbuild/3.1.0/build/coverlet.msbuild.targets(39,5): warning:
[coverlet] Unable to instrument module: xxx/xxx/xxx/xxx/xxx.dll because: 
AssemblyResolutionException for 'Microsoft.Extensions.Logging.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. 
Try to add <PreserveCompilationContext>true</PreserveCompilationContext> to test projects </PropertyGroup> or pass '/p:CopyLocalLockFileAssemblies=true' option to the 'dotnet test' command-line

As @304NotModified pointed out it seems that coverlet msbuild cannot find the DLL under bin/Debug/.net5.0. Even though the DLL is available in bin/Debug/.net5.0/refs, things only work when I manually copy the DLL file to the parent folder,bin/Debug/.net5.0. Is it the case that coverlet needs to scan the /refs folder as well to prevent this type of issue?

@304NotModified
Copy link
Contributor Author

If I understand it correctly,
<PreserveCompilationContext>true</PreserveCompilationContext> is creating the refs folder (or ref?), see https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#preservecompilationcontext

@MarcoRossignoli
Copy link
Collaborator

PreserveCompilationContext is used to emit information on deps files and help coverlet to try to resolve libs needed by Cecil.

https://github.com/MarcoRossignoli/coverlet/blob/master/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs#L173

If you're able to provide a repro I can try to improve this one.

@andrey-chernykh
Copy link

As workaround I'm using such test pipeline:

dotnet publish
cp -f ./bin/Debug/net6.0/refs/* ./bin/Debug/net6.0/
dotnet test --collect:\"XPlat Code Coverage\" -l:\"junit;LogFileName=results.xml\" -r /reports --settings coverlet.runsettings --diag /reports/test.log --no-restore

You can simplify the last string to dotnet test --collect:\"XPlat Code Coverage\" --no-restore

@304NotModified
Copy link
Contributor Author

304NotModified commented Nov 19, 2021

@MarcoRossignoli

I'm afraid that creating reproduction is hard.

I propose the following: coverlet tries to load from the refs folder, create a prerelease of coverlet, and I will be happy to test it :)

@MarcoRossignoli
Copy link
Collaborator

MarcoRossignoli commented Nov 20, 2021

Despite the fact that use publish+ref works I feel it too much as an "hack", I prefer something more useful in every scenario.
One idea I had also in past would be add a configuration that can be used by instrumentor for probing additional default directories. Something like typesresolutionpaths where a dev can in case of issues specify a list of path where to search if default paths don't work.

@adampaquette
Copy link

As additional information, I reproduce the problem in my library. Check the action associated with: adampaquette/Typely#28.

I have the following structure: Typely.EfCore depends on Typely.Core.
The project Typely.EfCore.Tests needs to instrument Typely.Core to fill the missing coverage on common functions.

@MarcoRossignoli
Copy link
Collaborator

fixed in #1449

@dovic95
Copy link

dovic95 commented Jan 9, 2024

I've referenced the latest nightly build version in my dotnet 8 solution and I still get the error for two projects:

Coverlet.Core.Exceptions.CecilAssemblyResolutionException: AssemblyResolutionException for 'Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Try to add true to test projects or pass '/p:CopyLocalLockFileAssemblies=true' option to the 'dotnet test' command-line
---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'
--- End of inner exception stack trace ---
at Coverlet.Core.Instrumentation.NetstandardAwareAssemblyResolver.TryWithCustomResolverOnDotNetCore(AssemblyNameReference name) in /_/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs:line 217

I have tried several workarounds, but the only one that works is copying the Microsoft.Extensions.Logging.Abstractions from the refs folder to the parent one, as suggested by @304NotModified.

Do you guys still have the issue? @MarcoRossignoli when you say that this issue is fixed in #1449, is there any specific thing to do to get rid of this issue?

@MarcoRossignoli
Copy link
Collaborator

MarcoRossignoli commented Jan 10, 2024

@lg2de any idea of the @dovic95 issue? I would expect that we try to scan all the shared framework installed and that lib should be there for asp.net core

"C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.1\Microsoft.Extensions.Logging.Abstractions.dll"

cc: @daveMueller @bert2

@lg2de
Copy link
Contributor

lg2de commented Jan 10, 2024

I'm currently not that motivated to investigate that issue again, because I was waiting half a year for a release of my fix.
Now, I switched (back) to MS coverage in my project...
I do not have an idea except that Microsoft has changed some detail with .NET 8.
IF I start investigation I would update the existing tests from net6 to net8.

@MarcoRossignoli
Copy link
Collaborator

Got it thanks @lg2de for the quick response and contributions to coverlet!

@mikejr83
Copy link

I just noticed that I wasn't getting code coverage for an assembly. I use Fine Code Coverage in Visual Studio and was taking a look at its logs. I found this exception:

Unable to instrument module: C:\projects\refunds-service\Firstech.Refunds.Tests\bin\Debug\net8.0\fine-code-coverage\build-output\Firstech.Refunds.API.Web.dll
Coverlet.Core.Exceptions.CecilAssemblyResolutionException: AssemblyResolutionException for 'Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Try to add <PreserveCompilationContext>true</PreserveCompilationContext> to test projects </PropertyGroup> or pass '/p:CopyLocalLockFileAssemblies=true' option to the 'dotnet test' command-line
 ---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'
   --- End of inner exception stack trace ---
   at Coverlet.Core.Instrumentation.NetstandardAwareAssemblyResolver.TryWithCustomResolverOnDotNetCore(AssemblyNameReference name) in /_/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs:line 215
   at Coverlet.Core.Instrumentation.NetstandardAwareAssemblyResolver.Resolve(AssemblyNameReference name) in /_/src/coverlet.core/Instrumentation/CecilAssemblyResolver.cs:line 127
   at Mono.Cecil.MetadataResolver.Resolve(TypeReference type)
   at Mono.Cecil.ModuleDefinition.Resolve(TypeReference type)
   at Mono.Cecil.TypeReference.Resolve()
   at Mono.Cecil.Mixin.CheckedResolve(TypeReference self)
   at Mono.Cecil.MetadataBuilder.GetConstantType(TypeReference constant_type, Object constant)
   at Mono.Cecil.MetadataBuilder.AddConstant(IConstantProvider owner, TypeReference type)
   at Mono.Cecil.MetadataBuilder.AddParameter(UInt16 sequence, ParameterDefinition parameter, ParamTable table)
   at Mono.Cecil.MetadataBuilder.AddParameters(MethodDefinition method)
   at Mono.Cecil.MetadataBuilder.AddMethod(MethodDefinition method)
   at Mono.Cecil.MetadataBuilder.AddMethods(TypeDefinition type)
   at Mono.Cecil.MetadataBuilder.AddType(TypeDefinition type)
   at Mono.Cecil.MetadataBuilder.AddTypes()
   at Mono.Cecil.MetadataBuilder.BuildTypes()
   at Mono.Cecil.MetadataBuilder.BuildModule()
   at Mono.Cecil.MetadataBuilder.BuildMetadata()
   at Mono.Cecil.ModuleWriter.<>c.<BuildMetadata>b__2_0(MetadataBuilder builder, MetadataReader _)
   at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
   at Mono.Cecil.ModuleWriter.BuildMetadata(ModuleDefinition module, MetadataBuilder metadata)
   at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
   at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
   at Mono.Cecil.ModuleDefinition.Write(Stream stream, WriterParameters parameters)
   at Coverlet.Core.Instrumentation.Instrumenter.InstrumentModule() in /_/src/coverlet.core/Instrumentation/Instrumenter.cs:line 337
   at Coverlet.Core.Instrumentation.Instrumenter.Instrument() in /_/src/coverlet.core/Instrumentation/Instrumenter.cs:line 153
   at Coverlet.Core.Coverage.PrepareModules() in /_/src/coverlet.core/Coverage.cs:line 135

I traced back in my commit history to where it started happening. The best I can tell is that I took a service that was for audit logging and changed its signature to take LogLevel:

        public Task IncomingRequestReceived(int clientId,
            AuditLoggingReqeuestType requestType,
            AuditLoggingRequestPurpose requestPurpose,
            string? message = null,
            string? queryString = null,
            string? requestBody = null,
            LogLevel logLevel = LogLevel.Debug)
        {
            this.logger.Log(logLevel,
                "Incoming request recieved: Request type {RequestType} - Request purpose {RequestPurpose} - Message {Message} - Query string: {QueryString} - Request Body {RequestBody}",
                requestType,
                requestPurpose,
                message,
                queryString,
                requestBody);

I'm using the Moq library and have some verifications setup:

            this.mockAuditLoggerService
                .Verify(s => s.IncomingRequestReceived(It.Is<int>(id => id == CLIENT_ID),
                    It.Is<AuditLoggingReqeuestType>(t => t == AuditLoggingReqeuestType.Refund),
                    It.Is<AuditLoggingRequestPurpose>(t => t == AuditLoggingRequestPurpose.Create),
                    It.IsAny<string?>(),
                    It.IsAny<string?>(),
                    It.IsAny<string?>(),
                    It.IsAny<LogLevel>()),
                    Times.Once());

Now, I don't know why this would make any difference. First I removed all the code in my test assembly that would reference the Microsoft.Extensions.Logging.LogLevel, Microsoft.Extensions.Logging.Abstractions enum. Running tests and code coverage gave me the same error. When I went through and reverted the service's interface and implementation to no longer use the enum and replace this.logger.Log(logLevel... with this.logger.LogDebug(... I was able to avoid the error and get results.

This is very interesting. I have ILogger throughout my test assembly and in every class. I thought that came from the abstractions assembly. Why using either the enum or ILogger.Log would cause this is beyond me. I'm pretty sure that Log method is an extension method just as LogDebug.

Hopefully this is helpful in some way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs repro Needs repro to be investigated, cannot repro in local
Projects
None yet
Development

No branches or pull requests

8 participants