I currently have several .Net windows services running on my server. Is there a way to attach a console app to the service to get all of the ILogger data? I have had issues where the service runs perfectly as a console app/worker service but as soon as I run it as a windows service, it just sits there and does nothing.
I did find an article about attaching the VS debugger to the process, but this will not work with our network security.
I am open to any other suggestions as well.
The technical answer is no, but as #Fildor mentioned, you would set up a log sink of some sort. The file logger is just an example, but you can also have the logs send emails, post to some cloud logging service such as splunk or cloudwatch, etc.
One issue you may run into is that you need to capture an error prior to ILogger being available and properly configured for you. Here is a guide I followed for capturing startup errors using NLog: https://alistairevans.co.uk/2019/10/04/asp-net-core-3-0-logging-in-the-startup-class-with-nlog/
Startup classes are no longer necessary in the latest .NET version, so I modified their example to be code you would have in Program.cs:
// NLog: setup the nlog config first
NLogBuilder.ConfigureNLog("nlog.config");
try
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
// Use NLog to provide ILogger instances.
.UseNLog()
.Build();
host.Run();
}
catch (Exception ex)
{
var logger = nlogLoggerProvider.CreateLogger(typeof(Program).FullName);
}
}
Here's the list of available log sinks you can configure in that nlog configuration file: https://nlog-project.org/config/
This same thing can be accomplished with other log providers you may already be using such as Serilog, Log4Net, etc.
Related
I wrote an Asp.Net Core app which is supposed to run as a MS-service in the back, however whenever I start it, it immediately stops. The URLs for my service are being read from a .config file and everything seems to work when normally starting my app.
I first published my app using Jetbrain's Rider with the following settings:
Then I tried to add it with the following command:
sc.exe create MyService binPath= "some\path\to\publish\to\MyService.exe"
It worked, and starting it via sc.exe start MyService also returned me a success message, however whenever I look at the list of services running in the Windows 10 tool, it says that my service stopped. Does the reading of URLs have something to do with it? If so, how else should I read my URLs from external sources?
Program.cs, CreateHostBuilder():
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
.ConfigureWebHost(config =>
{
//Set the urls and ports where the service should run.
config.UseUrls(Config.HttpsUrl, Config.HttpUrl);
//Run as MS service.
})
.UseWindowsService();
When adding it as a MS-service I looked at the following article.
I'm using ASP.NET Core data protection with default DI behavior. That works fine when my ASP.NET application is hosted on IIS. Now I have an application that needs to run as a service. So I'm using Microsoft.Extensions.Hosting.WindowsServices to do the windows service part with our standard
Host.CreateDefaultBuilder(args)
.UseWindowsService()
The BackgroundService then hosts ASP.NET Core with your standard
var builder = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("secrets.json", optional: true, reloadOnChange: true);
}
.ConfigureWebHostDefaults(....)
inside the background service, I can then resolve an instance of IDataProtectionProvider, create a protector, and use it to unprotect my secrets
var dataProtectionProvider = Container.Resolve<Microsoft.AspNetCore.DataProtection.IDataProtectionProvider>();
var protector = dataProtectionProvider.CreateProtector(appName);
var decryptedSecret = protector.Unprocect(some secret)
Now that all works fine as long as I run my application from the CLI. But running it as a service (same file, same location, and of course under the same account), I get an 'invalid payload' exception when I call Unprotect.
I know same path and same account is important, so that's taken care of. I also know that the application can find secrets.json as I wrote some probing code that checks if the file is present and can be read before I even try to unprotect. I'm even checking if the string I'm trying to unprotect is null/empty (which it isn't).
I finally installed a debug build as a service and attached the debugger, and when I look at IDataProtectionProvider, it has a Purpose.. and when running as a service, that's c:\windows\system32. When my app runs from the CLI, it's the path to the exe. So, is there a way to specify the purpose on my own so things behave the same regardless of CLI/Service?
So how can I control the purpose?
So having noted the difference in purpose of the IDataProtectionProvider, I was well on my way of solving this. The solution was to set a static purpose as explained here
I am adding Application Insights (AI) to my web API service by following this page Application Insights Instructions. I managed to get my service to connect to AI and I am able to see when my service preforms a post, get, etc. I also placed log calls through my service, but none of them are being written to my AI's Traces log.
I made sure to setup my Startup.cs and appsettings.json files to contain the new code needed to run AI in throughout my service, and the logging data need to have AI grab logs debug and up.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry();
}
appsettings.json
Logging Example
public async Task ProcessQueueAsync(dBData dbContext)
{
// _logger is of type ILogger<[INSERT CLASS NAME]>
_logger.LogDebug("This is a test log by Lotzi11.");
await ProcessQueueAsyncSingle(dbContext, CancellationToken.None);
}
Can someone help me figure out why my logs are not being sent to AI?
Your code configuration and appsettings.json are correct. I can see these logs in AI as per your settings at my side.
One thing you should know is that, it may take a few minutes for these data to arrive in AI server. Please wait for a few minutes, like 5 minutes or more, then query these data again from azure portal -> application insights.
And here is a simple way to check if the data is sent to AI. In visual studio, when running the project, you can search the logs in visual studio output window. If you can find the logs there, then it should be sent to AI:
Search in visual studio output window:
If you still cannot see the these logs in AI, you should also check if you have set something like filter or sampling in your code.
While I was working on solving my problem, I found out that my company uses Serilog to handle logging, so I had to alter my project so Serilog would also send logs to AI. I modified my code using the following page serilog-sinks-applicationinsights.
This led my to realize that even though I followed Microsofts instructions on setting up AI, my ILogger class is not properly setup to handle sending logs to AI. To fix that, I alter my Startup.cs's constructor:
public Startup(IHostEnvironment environment, IConfiguration configuration)
{
var env = new Environment(environment.EnvironmentName);
_systemConfiguration = new SystemConfiguration(env, configuration);
_systemConfiguration.Validate();
Log.Logger = new LoggerConfiguration().Enrich.FromLogContext().WriteTo.ApplicationInsights(_systemConfiguration.BaseConfiguration["APPINSIGHTS_INSTRUMENTATIONKEY"], TelemetryConverter.Traces).CreateLogger();
using var provider = new SerilogLoggerProvider(Log.Logger);
_logger = provider.CreateLogger(nameof(Startup));
}
After adding AI to Log.Logger, my logs began showing up in my AI's page.
So I am trying to run NLog on dotnet core (let's say 2.1.202) so I specifically want it to work with the console output stream. And I want to get as many messages as possible (yeah, logging..) so I've implemented a simple Tracer : TraceListener. So far so good and even if I try to run it via dotnet run it still works pretty well (everything is printed at console as it should be). However, if I try to run the web application via
dotnet publish
dotnet MyProjectName.dll
It fails. No log messages are actually being displayed and the project runs smoothly. So does anyone knows a way to print log messages on console via "publish" method.
Here is my Program.cs file (That's the only place where I mention Nlog, no specific services/configurations in Startup.cs)
public class Program
{
public static void Main(string[] args)
{
var host = BuildWebHost(args);
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
Trace.Listeners.Add(new Tracer(logger));
try
{
Trace.WriteLine("init main");
host.Run();
}
catch (Exception ex)
{
Trace.Fail(ex.ToString());
}
finally
{
NLog.LogManager.Shutdown();
}
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog()
.Build();
}
To be fair I've checked the given example from NLog and it actually works (from publish) but still I cannot find my problem in my app.
So if somebody done something like that and knows what I am missing here to run logs via publish it would be very helpful. Cheers!
So the problem was that there was internal second nlog.config (in a class library project) which was overriding my default nlog.config from the web project.
Shoutout to Julian for giving the idea to check internal nlog log - very helpful indeed.
As part of my application I have a .Net Core API project. Unlike most cases where this project would run as its own process, I have the API run in a thread, among others, in a single process. Also for my project, I have implemented a custom logging system to suit my needs. However, I have come across a slight problem. Every time I run my program, once the API starts, this message is printed to the console:
Hosting environment: Production
Content root path: C:\Users\Path\To\Code
Now listening on: http://*:8000
Application started. Press Ctrl+C to shut down.
I would like to disable this message as there is no need for it, and it clutters up the otherwise well organized console log. I have a screenshot below so you know exactly what I'm talking about:
I have already disabled all other logging for the mvc (removed ILoggerFactory from ConfigureServices and set all logging to "None" in appsettings.json).
How do I go about disabling/suppressing this message?
.NET Core 3.x
Good news!
These annoying messages are not being written by ASP.NET Core using plain Console anymore. Now abstract Logger is used, so startup messages will be written by your logger in configured format, just like any other logs.
But if you want to get rid of these logs all along, you can use one of two following approaches
The first way is to use .ConfigureLogging(...) method on host builder to remove all default providers from logger:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders(); // <-- here
})
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
The other way is to configure .NET Core 3 logger with ConsoleLifetimeOptions in your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.Configure<ConsoleLifetimeOptions>(opts => opts.SuppressStatusMessages = true);
// ...
}
NOTE: second approach won't disable Kestrel logs about an app being listened on port (but first will)
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://localhost:5000
.NET Core 2.x
These messages can be disabled in 2 ways (besides already mentioned console settings):
1) You can disable them with Environment variable:
"ASPNETCORE_SUPPRESSSTATUSMESSAGES": "true"
2) Or through code (in Program.cs):
WebHost.CreateDefaultBuilder(args)
.UseSetting(WebHostDefaults.SuppressStatusMessagesKey, "True")
or
WebHost.CreateDefaultBuilder(args)
.SuppressStatusMessages(true);
In ASP.NET Core 2.1, use the SuppressStatusMessages method on the WebHostBuilder.
WebHost.CreateDefaultBuilder()
.UseStartup<Startup>()
.SuppressStatusMessages(true);
You could also do this:
var host = BuildWebHost(args);
host.Start();
host.WaitForShutdown();
This will bypass the Console.WriteLine()s.
Removing logger factory won't help, because it is Console.WriteLine() (Ref : Github issue comment) . You need to suppress the Console.WriteLine outputs. In the Main method, write code like this. This will ignore the Console.WriteLine outputs.
public static void Main(string[] args)
{
Console.SetOut(new StreamWriter(Stream.Null));
BuildWebHost(args).Run();
}