How to configure a default target in NLog - nlog

I am trying to convert existing logging library used by a bunch of apps to use NLog. The existing logging code has no indirection, logging calls go straight from the caller to a webservice call. The existing logging code is implemented as a static singleton. I need to do this in such a way that existing applications that use this library do not need configuration or code changes when they pick up the changed logging library. Later I can go update applications on an as needed basis, configuring a new logging target or changing the code to log to NLog directly.
To do this, I was going to make the static logging code go through NLog. Existing logging calls will be routed through NLog, and the existing webservice call will be wrapped in a custom NLog target.
To make this work on legacy apps without changing them, I need to programmatically set the custom target as the default (when none are configured in a config file). I'd like to do this without making config changes on the numerous existing applications, so I need to do this programmatically.
The problem is... its not working. Any thoughts on this approach? Below is the code I tried to add to hook in the existing logger class to create the default target.
I wouldn't mind going to log4net either. Just looking at the APIs I chose NLog initially as the names made more sense to me.
public static class LegacyLogger
{
static LegacyLogger()
{
if (LogManager.Configuration == null
|| LogManager.Configuration.GetConfiguredNamedTargets().Count == 0)
{
if (LogManager.Configuration == null)
{
LogManager.Configuration = new LoggingConfiguration();
}
//LogManager.Configuration.AddTarget("LegacyLogger", new NLog.Targets.DebuggerTarget());
LogManager.Configuration.AddTarget("LegacyLogger", new LegacyLoggerTarget());
}
_logger = LogManager.GetCurrentClassLogger();
}

Ok, if you're new to NLog, as I was, be advised the examples installed with the installer cover about everything. In this case, I needed:
public static class LegacyLogger
{
static LegacyLogger()
{
if (LogManager.Configuration == null
|| LogManager.Configuration.GetConfiguredNamedTargets().Count == 0)
{
NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(new LegacyLoggerTarget(), LogLevel.Trace);
}
_logger = LogManager.GetCurrentClassLogger();
}

Related

setting micronaut configuration location

I have an existing groovy micronaut app I'm trying to change where it loads its config from. I don't understand what code to write so I can set the location of the micronaut configuration. I know you can use micronaut.config.files system variable or MICRONAUT_CONFIG_FILES environment variable, but this is a terrible idea because micronaut is built into grails and therefore every grails app you have running in tomcat will pick up the same config and crash.
Nor do I know where in the code to set the config file. There's an Application class with a run() method, but I don't know if this is only called during development, or whether it gets called when deploying in Tomcat. When setting the config in a Grails app, there is an Application class extending EnvironmentAware, and you can override setEnvironment, and load external configs there, but there is no hint of that for micronaut apps.
The micronaut doco says it can load a configuration from "application.{extension}", but it doesn't say what "application" is, or what directory it expects that in, or whether you can change the directory. Is "application" the value of micronaut.application.name in one's application.yml? I couldn't seem to get it to load based on that.
Then the documentation talks about loading from a PropertySource, which is fine and all, but doesn't tell you where you can put that code to load from a PropertySource. There is mention you can pass the PropertySource to ApplicationContext.run(xx), but in this app I inherited, there is no mention of ApplicationContext, and the micronaut documentation isn't very clear what I'm supposed to do with ApplicationContext. This app I've inherited has an Application class with a main() calling Micronaut.run() which apparently returns an ApplicationContext, but it's not clear if main() is called when running in Tomcat, or whether I should be calling run() on that, when it works as is, and I'm just trying to change where it loads its config.
The question is, how do I get my micronaut app to load its config from
where I tell it to, and not from micronaut.config.file system variable
location.
I don't think we have a specific feature in the framework that allows you to tell the framework to ignore micronaut.config.files. If you would like such a feature you can request it at https://github.com/micronaut-projects/micronaut-core/issues. If that is of interest I suggest you open it up for discussion at https://github.com/micronaut-projects/micronaut-core/discussions first.
You can load external config files, from a path not set as micronaut.config.files, in the main method of the Application class before running the application. Take a look at below class which accepts a config folder location as a system property demo.config.path(can be something else) and loads yaml config files from that folder:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import io.micronaut.context.env.PropertySource;
import io.micronaut.context.env.yaml.YamlPropertySourceLoader;
import io.micronaut.core.io.ResourceLoader;
import io.micronaut.core.io.file.DefaultFileSystemResourceLoader;
import io.micronaut.runtime.Micronaut;
public class Application {
private static final String PROP_CONFIG_LOCATION = "demo.config.path";
public static void main(String[] args) throws IOException {
if (System.getProperty(PROP_CONFIG_LOCATION) != null) {
List<PropertySource> propertySources = new ArrayList<>();
YamlPropertySourceLoader propertySourceLoader = new YamlPropertySourceLoader();
ResourceLoader resourceLoader = new DefaultFileSystemResourceLoader();
Files.newDirectoryStream(Paths.get(System.getProperty(PROP_CONFIG_LOCATION))).forEach(file -> {
String fileName = file.toString();
String fileNameWithoutExtension = fileName.substring(0, fileName.lastIndexOf('.'));
propertySourceLoader.load(fileNameWithoutExtension, resourceLoader).ifPresent(propertySources::add);
});
Micronaut.build(args)
.classes(Application.class)
.propertySources(propertySources.toArray(new PropertySource[1]))
.start();
} else {
Micronaut.run(Application.class, args);
}
}
}
As is, this code works for yaml config files(with snakeyaml in classpath). With minor changes, it can be made to work for properties files and to read config location from environment variable instead of system property. Full sample application present in github

How do I specify what would normally be in web.config for an Azure Function?

I'm creating an Azure Function, and I need to set this parameter what would normally go in the web.config file:
<entityFramework codeConfigurationType="xxxxxxxx">
But Azure Functions doesn't have a web.config. How do I configure stuff that isn't a simple key/value app setting?
The entity framework code is in a class library used by lots of other things, so I can't really use code based config without major hassle.
You can place it in your code. Microsoft documentation with all options is here: https://learn.microsoft.com/en-us/ef/ef6/fundamentals/configuring/code-based#moving-dbconfiguration
[DbConfigurationType(typeof(MyDbConfiguration))]
public class MyContextContext : DbContext
{
}
or
[DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssembly")]
public class MyContextContext : DbContext
{
}

Servicestack Multitenancy dynamic plugins

We are moving from an on premise-like application to a multi tenant cloud application.
for my web application we made a very simple interface based on IPlugin, to create a plugin architecture. (customers can have/install different plugins)
public interface IWebPlugin : IPlugin
{
string ContentBaseUrl { set; get; }
}
We have some plugins that would normally be loaded in on startup. Now i'm migrating the code to load at the beginning of a request (the Register function is called on request start), and scope everything inside this request.
It's not ideal but it would bring the least impact on the plugin system for now.
I could scope the Container by making an AppHost child container which would stick to the request:
Container IHasContainer.Container
{
get
{
if (HasStarted)
return ChildContainer;
return base.Container;
}
}
public Container ChildContainer
{
get { return HttpContext.Current.Items.GetOrAdd<Container>("ChildContainer", c => Container.CreateChildContainer()); }
}
problem case
Now im trying to make plugins work that actually add API services.
appHost.Routes.Add<GetTranslations>("/Localizations/translations", ApplyTo.Get);
But this service is unreachable (and not visible in metadata). How do i make it reachable?
I see you execute the following in ServiceController AfterInit. Re-executing this still wouldnt make it work.
//Copied from servicestack repo
public void AfterInit()
{
//Register any routes configured on Metadata.Routes
foreach (var restPath in appHost.RestPaths)
{
RegisterRestPath(restPath);
//Auto add Route Attributes so they're available in T.ToUrl() extension methods
restPath.RequestType
.AddAttributes(new RouteAttribute(restPath.Path, restPath.AllowedVerbs)
{
Priority = restPath.Priority,
Summary = restPath.Summary,
Notes = restPath.Notes,
});
}
//Sync the RestPaths collections
appHost.RestPaths.Clear();
appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x));
appHost.Metadata.AfterInit();
}
solution directions
Is there a way i could override the route finding? like extending RestHandler.FindMatchingRestPath(httpMethod, pathInfo, out contentType);
Or could i restart the path compilation/caching? (would be enough for now that the service would be reachable tenant wide )
All configuration in ServiceStack should be contained within AppHost.Configure() and remain immutable thereafter. It's not ThreadSafe to modify ServiceStack's Static Configuration at runtime like trying to modify registered routes or Service Metadata which needs to be registered once at StartUp in AppHost.Configure().
It looks as though you'll need to re-architect your solution so all Routes are registered on Startup. If it helps Plugins can implement IPreInitPlugin and IPostInitPlugin interfaces to execute custom logic before and after Plugins are registered. They can also register a appHost.AfterInitCallbacks to register custom logic after ServiceStack's AppHost has been initialized.
Not sure if it's applicable but at runtime you can "hi-jack Requests" in ServiceStack by registering a RawHttpHandler or a PreRequestFilter, e.g:
appHost.RawHttpHandlers.Add(httpReq =>
MyShouldHandleThisRoute(httpReq.PathInfo)
? new CustomActionHandler((req, res) => {
//Handle Route
});
: null);
Simple answer seems to be, no. The framework wasn't build to be a run-time plugable system.
You will have to make this architecture yourself on top of ServiceStack.
Routing solution
To make it route to these run-time loaded services/routes it is needed to make your own implementation.
The ServiceStack.HttpHandlerFactory checks if a route exist (one that is registered on init). so here is where you will have to start extending. The method GetHandlerForPathInfo checks if it can find the (service)route and otherwise return a NotFoundHandler or StaticFileHandler.
My solution consists of the following code:
string contentType;
var restPath = RestHandler.FindMatchingRestPath(httpMethod, pathInfo, out contentType);
//Added part
if (restPath == null)
restPath = AppHost.Instance.FindPluginServiceForRoute(httpMethod, pathInfo);
//End added part
if (restPath != null)
return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
technically speaking IAppHost.IServiceRoutes should be the one doing the routing. Probably in the future this will be extensible.
Resolving services
The second problem is resolving the services. After the route has been found and the right Message/Dto Type has been resolved. The IAppHost.ServiceController will attempt to find the right service and make it execute the message.
This class also has init functions which are called on startup to reflect all the services in servicestack. I didn't found a work around yet, but ill by working on it to make it possible in ServiceStack coming weeks.
Current version on nuget its not possible to make it work. I added some extensibility in servicestack to make it +- possible.
Ioc Solution out of the box
For ioc ServiceStack.Funq gives us a solution. Funq allows making child containers where you can register your ioc on. On resolve a child container will, if it can't resolve the interface, ask its parent to resolve it.
Container.CreateChildContainer()

Configuration of options from IConfigurationRoot not working?

The following code is snipped from the examples at docs.asp.net.
public void ConfigureServices(IServiceCollection services)
{
// Setup options with DI
services.AddOptions();
// Configure MyOptions using config
services.Configure<MyOptions>(Configuration);
// Configure MyOptions using code
services.Configure<MyOptions>(myOptions =>
{
myOptions.Option1 = "value1_from_action";
});
The call to services.Configure<MyOptions>(Configuration);
causes a compilation error:
cannot convert from 'Microsoft.Extensions.Configuration.IConfigurationRoot' to 'System.Action'
Manually setting up the options works fine. Am I missing something really obvious here?
I had the same problem and I found out you need to add this extension to your project :
Microsoft.Extensions.Options.ConfigurationExtensions
You need to add the following nuget package to your ASP Core Project if you want to configure the strongly typed config in that way.
Microsoft.Extensions.Options.ConfigurationExtensions
The extension methods contained in the package will allow you to configure the strongly typed configuration the way you want to and the way most tutorials show.
services.Configure<MyOptions>(Configuration);
Alternatively, you could add another binder package:
Microsoft.Extensions.Configuration.Binder
Configuration would then look something like this:
services.AddOptions();
services.Configure<MyOptions>(x => Configuration.Bind(x));
This is the downside of having so many modular packaged up extensions. It gets easy to lose track of where functionality exists.

Ninject dependency injection in SharePoint Timer Job

I have successfully implemented an enterprise SharePoint solution using Ninject dependency injection and other infrastructure such as NLog logging etc using an Onion architecture. With a HttpModule as an Composition Root for the injection framework, it works great for normal web requests:
public class SharePointNinjectHttpModule: IHttpModule, IDisposable
{
private readonly HttpApplication _httpApplication;
public void Init(HttpApplication context)
{
if (context == null) throw new ArgumentException("context");
Ioc.Container = IocContainerFactory.CreateContainer();
}
public void Dispose()
{
if(_httpApplication == null) return;
_httpApplication.Dispose();
Ioc.Container.Dispose();
}
}
The CreateContainer method loads the Ninject modules from a separate class library and my ioc container is abstracted.
For normal web application requests I used a shared static class for the injector called Ioc. The UI layer has a MVP pattern implementation. E.g in the aspx page the presenter is constructed as follows:
presenter = Ioc.Container.Get<SPPresenter>(new Ninject.Parameters.ConstructorArgument("view", this));
I'm still reliant on a Ninject reference for the parameters. Is there any way to abstract this, other than mapping a lot of methods in a interface? Can't I just pass in simple types for arguments?
The injection itself works great, however my difficulty comes in when using external processes such as SharePoint Timer Jobs. It would obviously be a terrible idea to reuse the ioc container from here, so it needs to bootstrap the dependencies itself. In addition, it needs to load the configuration from the web application pool, not the admin web application. Else the job would only be able to run on the application server. This way the job can run on any web server, and your SharePoint feature only has to deploy configurations etc. to the web apllication.
Here is the execute method of my timer job, it opens the associated web application configuration and passes it to the logging service (nlog) and reads it's configuration from the external web config service. I have written code that reads a custom section in the configuration file and initializes the NLog logging infrastructure.
public override void Execute(Guid contentDbId)
{
try
{
using (var ioc = IocContainerFactory.CreateContainer())
{
// open configuration from web application
var configService = ioc.Get<IConfigService>(new ConstructorArgument("webApplicationName", this.WebApplication.Name));
// get logging service and set with web application configuration
var logginService = ioc.Get<ILoggingService>();
logginService.SetConfiguration(configService);
// reapply bindings
ioc.Rebind<IConfigService>().ToConstant(configService);
ioc.Rebind<ILoggingService>().ToConstant(logginService);
try
{
logginService.Info("Test Job started.");
// use services etc...
var productService = ioc.Get<IProductService>();
var products = productService.GetProducts(5);
logginService.Info("Got products: " + products.Count() + " Config from web application: " + configService.TestConfigSetting);
logginService.Info("Test Job completed.");
}
catch (Exception exception)
{
logginService.Error(exception);
}
}
}
catch (Exception exception)
{
EventLog.WriteError(exception, "Exception thrown in Test Job.");
}
}
This does not make the timer jobs robust enough, and there is a lot of boiler plate code. My question is how do I improve on this design? It's not the most elegant, I'm looking for a way to abstract the timer job operation code and have it's dependencies injected into it for each timer job. I would just like to hear your comments if you think this is a good approach. Or if someone has faced similar problems like this? Thanks
I think I've answered my own question with the presenter construction code above. When using dependency injection in a project, the injection itself is not that important, but the way it changes the way you write code is far more significant. I need to use a similar pattern such as command for my SharePoint timer job operations. I'd just like the bootstrapping to be handled better.

Resources