question

ThomasGssi-7359 avatar image
0 Votes"
ThomasGssi-7359 asked ThomasGssi-7359 commented

Access To LoggerProvider From Inside A HostedService (ServiceHost)

In .Net 5.0, logs are handled by ILogger and LoggerProvider. I have created a LoggerProvider, which writes logs into a memory list eg. stringlist. Now I want to access to this memory from within the hosted service.
How can I access to the LoggerProvider instance, so that I can access the log list inside by a property.

My LoggerProvider is:

 public class MyLoggerProvider : ILoggerProvider
 {    
     private List<string> _logList = new List<string>();
            
     public List<string> LogList
     {
         get
         {
             return _logList;
         }
     }
    
         public MyLoggerProvider()
         {
             _logList = new List<string>();
         }
    
         public ILogger CreateLogger(string className)
         {
             return new ServiceLogger(this, className);
         }
    
         public bool IsEnabled(LogLevel logLevel)
         {
             return true;
         }
    
         public void AddLogEntry(string logMessage)
         {
         _logList.Add( $"{DateTime.Now:f} :: {logMessage}" );
         }
    
         public void Dispose()
         {
         _logList~.Clear
         }
     }

And I initialize the ServiceHost with:

 public static void Main(string[] args)
 {
     CreateHostBuilder(args).Build().RunAsync();
 }
    
 public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureServices((hostContext, services) =>
         {
             services.AddHostedService<ServiceHost>();
             services.Configure<HostOptions>((option) =>
             {
                 option.ShutdownTimeout = TimeSpan.FromMinutes(10);
             });
         })
         .ConfigureLogging((hostContext, logging) =>
         {
             logging.AddProvider(new GuiLoggerProvider());
         })
         .UseWindowsService();

Then I want to access the LogList within the ServiceHost, which is:

 public class ServiceHost : IHostedService
 {
     private readonly IHost _host;
     private readonly IHostApplicationLifetime _hostApplicationLifetime;
     private readonly IConfiguration _configuration;
     private readonly ILogger _logger;
     private readonly ServiceWorker _serviceWorker;
    
     public ServiceHost(IHost host, IHostApplicationLifetime hostApplicationLifetime, IConfiguration configuration, ILoggerFactory logger)
     {
         _host = host;
         _hostApplicationLifetime = hostApplicationLifetime;
         _configuration = configuration;
         _logger = logger.CreateLogger(_configuration["AppSettings:ApplicationName"]);
         _serviceWorker = new ServiceWorker(_logger);
     }
    
     public Task StartAsync(CancellationToken cancellationToken)
     {
         myLoggerProvider =     /* Here I want to access to myLoggerProvider instance */
         List<string> myLogList = myLoggerProvider.LogList;
     }
 }

How can I access the MyLoggerProvider instance ?
Is that possible over the IHost _host or should I use the ILogger _logger ?


dotnet-csharpwindows-server
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

DuaneArnold-0443 avatar image
0 Votes"
DuaneArnold-0443 answered

_logger = logger.CreateLogger(_configuration["AppSettings:ApplicationName"]);

It is the only instance of a logger object in your code you are talking about. You should set a debug breakpoint just after the line and use debug Quickwtatch to look at the content of _logger object and see what is in it.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

ThomasGssi-7359 avatar image
0 Votes"
ThomasGssi-7359 answered ThomasGssi-7359 commented

Yes, I only have one logger instance created within my hosted service, but there are also other loggers instantiated namely the standard loggers of the MS-hosted server.
I may also have multiple logger providers in my project in the future, but I only have to acces the one with the memory.

However, I checked, what's in the logger instance. There are 3 Logger arrays:

 - Loggers  (of type LoggerInformation)
 - MessageLoggers (of type MessageLogger)
 - ScopeLoggers (of type ScopeLogger)

Within the Loggers I have 6 items, which I think, are the loggers of the project, also built ins like console logger, debug logger, etc.
Within the MessageLoggers, I also have 6 loggers, however, I could find myLoggerProvider in this list.
ScopeLoggers are for Scope, however, I also find my provider in that list, as I use scope.

That's, OK

But as these properties are not accessable by standard, I should use reflection to access it as well as I have to loop through all items to find MyLoggerProvider.

Do you have an idea if there is another, simpler way to access MyLogerProvider?

Eg. I have to use the right type of _logger to make these properties accessible.

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

You need to take a screen shot of the Quickwatch window with the content of the object and the area you are talking about and post it so I can see what you are talking about.

0 Votes 0 ·

Here are the quickwatch windows:

In _logger I have 3 arrays:

79428-grafik.png


If I open the Loggers, there are 6 elements of LoggerInformation:

79310-grafik.png


There I can find MyLoggerProvider in the 4th indexed element:

79429-grafik.png


But I can also open the MessageLoggers with also 6 elements of type MessageLogger in it:

79543-grafik.png


And the MyLoggerProvider is in the 4th indexed element again, accessible by Logger:

79534-grafik.png


Should I now access MyLoggerProvider by Loggers-LoggerInformation or by MessageLoggers-MessageLogger ?
Which one is better ?

I see, that the instantiated type of _logger is Microsoft.Extensions.Logging.Logger, but if I want to cast it to that type, the development system requests Microsoft.Extensions.Logging.Logger<> as generic. The instantiated type is not generic, so I cannot cast.

So how can I access the properties ?
However, I can use reflection to get it, but accessing by type is even better.
Or is there a way by dependency injection ?

0 Votes 0 ·
grafik.png (5.3 KiB)
grafik.png (9.8 KiB)
grafik.png (19.1 KiB)
grafik.png (11.2 KiB)
grafik.png (17.3 KiB)
DuaneArnold-0443 avatar image
0 Votes"
DuaneArnold-0443 answered ThomasGssi-7359 commented

var data = _logger.MessageLoggers[4].Logger._className;

OR example --- _logger.MessageLoggers[4].Logger._loggerProvider.

I can't see any properties for _loggerProvider in the screen shot.

============================================

foreach (var item in_logger.MessageLoggers)
{
var data = item.Logger._className;
}

===================================

for(int i = 0; i <_logger.MessageLoggers.Count(); i++)
{
var data = _logger.MessageLoggers[i].className;
}

It's just a strong typed collection within ._logger

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi
OK, acess by MessageLoggers.
Here is the screenshot with properties for _loggerProvider:

80624-grafik.png



But how can I access to MessageLoggers or _logger.MessageLoggers respectively. The _logger is of type ILogger.
To which type Have I to cast ?

0 Votes 0 ·
grafik.png (40.3 KiB)
DuaneArnold-0443 avatar image
0 Votes"
DuaneArnold-0443 answered ThomasGssi-7359 commented

But how can I access to MessageLoggers or _logger.MessageLoggers respectively. The _logger is of type ILogger.
To which type Have I to cast ?

You can use var and let the compiler to the cast to a type

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var

var data = _logger.MessageLoggers[4].Logger._className;

The data is going to be of type string.

You can use var in the local scope and the complier will to the cast.

You can stop on a line in the debugger and use the mouse pointer and hover over a var and Visual Stuido will tell you the type. You can use the type shown and make a cast to the type if you need to do it manually for some reason.


· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The problem is, I cannot access the property MessageLoggers.

Logger is:
80812-grafik.png

which is the non generic type of Microsoft.Extensions.Logging.Logger.

But I can only find Microsoft.Extensions.Logging.Logger<> as a generic type. I cannot cast from non generic to generic type.

When I use var, the compiler does not recognize MessageLoggers, as the function CreateLogger returns the type ILogger, which is then used in the var variable.

I also cannot find the type Microsoft.Extensions.Logging.MessageLogger.

Or do I miss any nuget package ?

0 Votes 0 ·
grafik.png (1.8 KiB)

I don't see why you cannot loop through the collection using a loop or going after an item in the collection via an index.

0 Votes 0 ·

The Problem is:
_logger is of type ILogger.

 var messageLoggers = _logger.MessageLoggers;

results in Compiler error.
ILogger does not contain a definition for MessageLoggers.

When I try to cast:

 var myLogger = _logger.as Microsoft.Extension.Logging.Logger<MyLoggerProvider>;
 var myLogger = _logger as Microsoft.Extension.Logging.Logger<ILogger>;

all of them result to NULL.

When I try to use the non-generic:

 var myLogger = _logger as Microsoft.Extension.Logging.Logger;

result in Compiler error, as Microsoft.Extension.Logging.Logger non-generic is not found or is inaccessible due to its protection level respectively.









0 Votes 0 ·

And what is the purpose of you doing this? And why can't you use something like Serilog that uses ILogger?

0 Votes 0 ·