Ninject with Log4Net extensions via TaskScheduller no logging output and no error - ninject

I have a console application project that is using Ninject and Log4Net.
When i run the app on my machine, the logging is working fine. When i run the app on the production server, the logging is working fine. When i run the program via TaskScheduller task which is being set so that is is being run by some other user, i get no logging output by any of the appenders. I'm using RollingFileAppender, SmtpAppender and AdoNetAppender.
The strange thing is, that the program is running fine, it just doesnt log anything.
I presume that because the app is working if i run it locally, the log4net configuration is fine.
I resolve logger in the main method of the program and then inject it via constructor parameter when needed. This is how i get the logger in the main method of the app:
XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config"));
var kernel = new StandardKernel();
var loggerFactory = kernel.Get<Log4NetLoggerFactory>();
ILogger logger = loggerFactory.GetCurrentClassLogger();
logger.Info(" Test ");
Any hints, pointers or anything....as i don't know what else to try.

The extension is normally used like this:
public class MyClass
{
private readonly ILogger log;
public MyClass(ILogger log)
{
this.log = log;
log.Info("Created MyClass");
}
}
XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config"));
using (IKernel kernel = new StandardKernel())
{
kernel.Bind<MyClass>().ToSelf();
kernel.Get<MyClass>(); // will cause the log message to print
}
Just let Ninject worry about injecting the ILogger into your class. You can't request an ILogger from the IKernel in the same place you declare the kernel because you've got no context.
You can do this though:
ILogger log = new Log4NetLoggerFactory().GetCurrentClassLogger();
log.Info("Test");

Related

how to send logging data to app insights from a library project

I have an aspnet core 2 web app which relies on a "Business" project to handle some logic. I am trying to set up the web app so that its ILogger logs are sent to App Insights. I can send the logs fine if I call the logger.Log method from within its Controller Actions. However, when making calls to classes in another project, which is part of the same solution, where I have an instance of ILogger and logging from there, it doesn't send any log data to App Insights. Am I missing something here? I would imagine if I have configured the logging and app insights in the web app correctly, I can call any other library from there and the logging data would be sent fine.
Approach 1 -
You will have to register your business logic class in Core API project in Startup; something similar to below
builder.Services.AddScoped<IMyClass, MyClass>();
And you will have to define a constructor which takes an ILogger instance in your business class; something like below
private readonly ILogger<MyClass> _logger;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
// _logger.LogInformation("Hi from MyClass"); e.g. logging
This approach means ILogger will be injected with all required settings into your business lib.
Approach 2 -
You will have to install the AppInsights worker package in your business lib project
Microsoft.ApplicationInsights.WorkerService
from here
Then, you will have to write code for logging into AppInsights, something like below
var serviceCollection = new ServiceCollection();
serviceCollection.AddApplicationInsightsTelemetryWorkerService(options => options.ConnectionString = "my-key");
serviceCollection.AddLogging(builder => builder
.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Information)
.AddFilter("Default", LogLevel.Information)
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
);
var serviceProvider = serviceCollection.BuildServiceProvider();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
var telemetryClient = serviceProvider.GetService<TelemetryClient>();
var logger = loggerFactory.CreateLogger("my-logger");
logger.LogInformation("Hi from MyClass");
// flush and sleep at the end, before returning to the caller so that no messages are lost
telemetryClient.Flush();
System.Threading.Thread.Sleep(5000);
You would need the Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Logging packages in your business lib project for this approach. This approach means you will write appinsights logging independently to your lib project.

Read Config From Another Project - Log4Net ASP.NET Core 3.1

I am trying to write a class library that uses log4net that looks something like this:
public class Logging
{
private ILog log4netLogger = null;
public Logging(Type type)
{
XmlDocument log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead("log4net.config"));
var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
XmlConfigurator.Configure(repo, log4netConfig["log4net"]);
log4netLogger = LogManager.GetLogger(type);
}
public void Debug(string message)
{
log4netLogger(message);
}
public void Info(string message)
{
log4netLogger(message);
}
}
However, the xml configuration is in my test console app in C:\....\TestLogging\TestLog4Net\bin\Debug\netcoreapp3.1. I actually started with this console app to test log4net but I have moved all my code from the main method of Program.cs to the Logging.cs constructor, but I think the LogManager will not be able to find this now.
Is this at all possible?
I think it is possible. To use the log4net in the class library, you have to install the log4net package in the class library, then, you could add the class library reference in the console application and use the class library method. But, as you said, the log4net.config file should be in the console application netcoreapp3.1 folder, otherwise, the class library will not find the log4net.config file:

How to configure hangfire with unity?

I have ASP.NET Web API application. The application is using Unity as IoC container. The application is also using Hangfire and I am trying to configure Hangfire to use Unity.
So based on documentation i am using Hangfire.Unity which registers the unity container as a current job activator in Hangfire.
I have a class which has dependency on IBackgroundJobClient
public class MyService
{
private MyDBContext _dbContext = null;
private IBackgroundJobClient _backgroundJobClient = null;
public MyService(MyDbContext dbContext, IBackgroundJobClient backgroundJobClient)
{
_dbContext = dbContext;
_backgroundJobClient = backgroundJobClient;
}
}
However even after configuring Hangfire.Unity it could not create & pass instance of BackgroundJobClient
So i had to register every dependency of BackgroundJobClient with unity container.
Unity Registration
public class UnityConfig
{
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<MyDbContext>(new HierarchicalLifetimeManager(), new InjectionFactory(x => new MyDbContext()));
// register hangfire dependencies
container.RegisterType<IBackgroundJobClient, BackgroundJobClient>();
container.RegisterType<JobStorage, SqlServerStorage>(new InjectionConstructor("HangfireConnectionString"));
container.RegisterType<IJobFilterProvider, JobFilterAttributeFilterProvider>(new InjectionConstructor(true));
container.RegisterType<IBackgroundJobFactory, BackgroundJobFactory>();
container.RegisterType<IRecurringJobManager, RecurringJobManager>();
container.RegisterType<IBackgroundJobStateChanger, BackgroundJobStateChanger>();
}
}
OWIN Startup
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = UnityConfig.GetConfiguredContainer();
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("HangfireConnectionString");
Hangfire.GlobalConfiguration.Configuration.UseUnityActivator(container);
// if i dont call UseSqlServerStorage() above then UseHangfireDashboard() method fails with exception
//JobStorage.Current property value has not been initialized. You must set it before using Hangfire Client or Server API.
app.UseHangfireDashboard();
app.UseHangfireServer();
RecurringJob.AddOrUpdate<MyService>(x => x.Prepare(), Cron.MinuteInterval(10));
}
}
Code is working with such configuration. However i have questions:
Is this the correct way of configuring Unity with Hangfire?
Why do i need to invoke Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("HangfireConnectionString") in OWIN startup even though SqlServerStorage is already registered with Unity container as JobStorage?
If i dont invoke UseSqlServerStorage() method in OWIN startup then i get exception on app.UseHangfireDashboard() method.
JobStorage.Current property value has not been initialized. You must
set it before using Hangfire Client or Server API.
I believe there is a problem where you want to kick off Hangfire outside of the Unity ecosystem, but also want Unity to understand how to instantiate the appropriate Hangfire interfaces with the associated implementations. Since Hangfire itself doesn't use Unity, you will need to start up Hangfire with the appropriate configuration, such as the SQL Server connection string, and then use that configuration to inform Unity how to instantiate the Hangfire interfaces. I was able to solve this problem by setting the global Hangfire configuration for SQL and then use that same Hangfire static instance to set up Unity.
Here's example code where first you will see how I start the hangfire dashboard and server with a connection string:
public void Configuration(IAppBuilder app)
{
var configuration = new Configuration(); // whatever this is for you
GlobalConfiguration.Configuration.UseSqlServerStorage(
configuration.GetConnectionString());
GlobalConfiguration.Configuration.UseActivator(
new HangfireContainerActivator(UnityConfig.GetConfiguredContainer()));
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] {new HangfireAuthorizationFilter()}
});
app.UseHangfireServer();
}
As the second example, here's the configuration of Unity for Hangfire; notice how this code is using the static JobStorage Hangfire object to instantiate any requests for JobStorage.
public static void RegisterHangfire(IUnityContainer container)
{
container.RegisterType<JobStorage>(new InjectionFactory(c => JobStorage.Current));
container.RegisterType<IJobFilterProvider, JobFilterAttributeFilterProvider>(new InjectionConstructor(true));
container.RegisterType<IBackgroundJobFactory, BackgroundJobFactory>();
container.RegisterType<IRecurringJobManager, RecurringJobManager>();
container.RegisterType<IBackgroundJobClient, BackgroundJobClient>();
container.RegisterType<IBackgroundJobStateChanger, BackgroundJobStateChanger>();
}
I believe this approach gives you the best of both worlds where you only set up your SQL Server connection once and you do it early to kick off Hangfire, but then you use that instance to tell Unity how to behave.

Log hangfire events using existing serilog

Im new to hangfire, and im trying to setup a way to log the events using my existing serilog logger in an asp.net web api. Here is my logger class:
public static class LoggerInitializer
{
private static ILogger CreateLog()
{
var settings = Settings.Instance;
Log.Logger = new LoggerConfiguration().
MinimumLevel.Debug().
WriteTo.RollingFile(settings.LoggerDebugDirectory +"Debug-{Date}.txt", restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Debug,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}").
WriteTo.RollingFile(settings.LoggerVerboseDirectory + "Debug-{Date}.txt").
CreateLogger();
return Log.Logger;
}
static ILogger _logger;
public static ILogger GetLogger()
{
if (_logger != null)
return _logger;
return _logger = CreateLog();
}
}
and in my startup file I add the code from the hangfire documentation:
GlobalConfiguration.Configuration
.UseSqlServerStorage(Settings.Instance.NLSContextConnectionString);
app.UseHangfireDashboard();
app.UseHangfireServer();
My hangfire works perfectly, but how do i enable make hangfire use my serilog?
It's possible that Hangfire is initializing and caching its own internal logger before CreateLog() is being called by the application.
To test this theory, try moving the code that initializes Log.Logger to the very beginning of the app's startup code, e.g. in Global.Application_Start() or similar.
In Hangfire 1.6.19 (and maybe before that, I did not check) adding the NuGet Package to your project gives you an extension method on IGlobalConfiguration :
configuration.UseSerilogLogProvider();

Cannot access RavenDB Management Studio

Try:
I created a new project in VS2012
I installed via the NuGet package RavenDB Embedded -Pre
I installed Ninject.MVC3
Added a module for ninject RavenDB:
Public class RavenDBNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IDocumentStore>().ToMethod(context =>
{
NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(8080);
var documentStore = new EmbeddableDocumentStore { Url="http://localhost:8080/", DataDirectory="~/App_Data", UseEmbeddedHttpServer = true };
return documentStore.Initialize();
}).InSingletonScope();
Bind<IDocumentSession>().ToMethod(context => context.Kernel.Get<IDocumentStore>().OpenSession()).InRequestScope();
}
}
In my class "NinjectWebCommon" ...
private static void RegisterServices(IKernel kernel)
{
kernel.Load(new RavenDBNinjectModule());
}
When running the application, the following url was generated ("http://localhost:1423")
Verify that the file "Raven.Studio.xap" was the root of my application
I tried accessing "http://localhost:8080" but the following screen is displayed:
What am I doing wrong?
As it turned out, the issue is that documentStore.Initialize never get called, because that no one did ask Ninject to resolve IDocumentStore.
You are setting the Url property, which means that you aren't running in embedded mode, but in server mode.
Remove the Url property, and everything will work for you.
I found the problem!
Since he had used IDocumentSession in no time, the ninject had not created the instance of IDocumentStore and thus not run the Initialize method