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

Kernel panic with debug output of InterfaceMethodId not found. #213

Open
Guillermo-Santos opened this issue Dec 25, 2023 · 6 comments
Open

Comments

@Guillermo-Santos
Copy link

Guillermo-Santos commented Dec 25, 2023

I have a logging implementation that use two interfaces and implement all the methods, building is done correctly but at runtime i get a kernel panic indicating that an interface method is not found. Quite strange behavior.

Type
0x0000028D
TypeName: Zaphyros.Core.Logging.MultiTargetLogger, Zaphyros.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
InterfaceMethodId
0x0000033A
Not FOUND!

Implementation can be found on Zaphyros's logging feacture branch

@Guillermo-Santos
Copy link
Author

Discovered that this issue happens when using an interface or abstract class (at least that is qhat it seens to be) when instantiating the logger with its type intead of the interface and called the Log method directly, it worked correctly.

@Guillermo-Santos
Copy link
Author

Guillermo-Santos commented Dec 28, 2023

This is just a crazy teory, but what if my Logger is parsed before the interface? That is the only way is see the methods id to be different. Or does IL2CPU checks if the interfaces and classes implemented were already parsed to use the same id for the methods?

@quajak
Copy link
Member

quajak commented Dec 31, 2023

Could you please make a simple reproducible code sample to make the issue apparent and debug-able?

@Guillermo-Santos
Copy link
Author

Could you please make a simple reproducible code sample to make the issue apparent and debug-able?

Of course, this is the code sample:
Using the Object as the interface:

var logger = (ILogger)new Logger("Kernel"); // Here a message is printed from the ctor, just to show that the method is really implemented.
// Fails on next line with method not found...
logger.Log(LogLevel.Information, 1, "", null, (string state, Exception? error) => "Cosmos booted successfully. Type a line of text to get it echoed back.");
logger.LogInformation("Hola Mundo");

Using Object Directly:

var logger = new Logger("Kernel"); // Here a message is printed from the ctor, just to show that the method is really implemented.
// This one Prints right
logger.Log(LogLevel.Information, 1, "", null, (string state, Exception? error) => "Cosmos booted successfully. Type a line of text to get it echoed back.");
// This extension Method of the interfaces fails.
logger.LogInformation("Hola Mundo");

Logger Class Code:

public sealed class Logger : ILogger
{
    private readonly string _categoryName;

    public Logger(string categoryName)
    {
        _categoryName = categoryName;
        Log(LogLevel.Debug, 0, "Creating new Logger", null, (string state, Exception? error) => state.ToString());
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
    {
        if (!this.IsEnabled(logLevel))
        {
            return;
        }

        var foregroundColor = Console.ForegroundColor;
        Console.ForegroundColor = logLevel switch
        {
            LogLevel.Trace => ConsoleColor.DarkCyan,
            LogLevel.Debug => ConsoleColor.Cyan,
            LogLevel.Information => ConsoleColor.Green,
            LogLevel.Warning => ConsoleColor.Yellow,
            LogLevel.Error or LogLevel.Critical => ConsoleColor.Red,
            _ => foregroundColor,
        };
        Console.Write($"[{GetLogLevelString(logLevel)}]");
        Console.ForegroundColor = foregroundColor;
        Console.Write(": ");
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine(_categoryName);
        Console.ForegroundColor = foregroundColor;
        Console.WriteLine($"\t{formatter(state, null)}");
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        // In a real logger, you might implement more sophisticated logic based on log level.
        return true;
    }

    public IDisposable? BeginScope<TState>(TState state) where TState : notnull
    {
        return null;
    }
    private static string GetLogLevelString(LogLevel logLevel)
    {
        return logLevel switch
        {
            LogLevel.Debug => "DEBUG",
            LogLevel.Trace => "TRACE",
            LogLevel.Information => "INFO",
            LogLevel.Warning => "WARN",
            LogLevel.Error => "ERROR",
            LogLevel.Critical => "CRITICAL",
            LogLevel.None => string.Empty,
            _ => throw new ArgumentOutOfRangeException(nameof(logLevel)),
        };
    }
}

The problem really is on any use of the interface.

@Guillermo-Santos
Copy link
Author

Guillermo-Santos commented Jan 1, 2024

the ILogger interface and the extension method used are from Microsoft.Extensions.Logging nugget package

@Guillermo-Santos
Copy link
Author

this is a crazy assumption, but could it be that it is detecting the method as private for the interface? as it does not have it explicitly on the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants