My log4net configuration is this,
<?xml version="1.0" encoding="utf-8" ?>
<log4netConfiguration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<appSettings>
<add key="log4net.Config" value="log4net.config" />
</appSettings>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\my_logs/my_web_logs/my_log_%date{ddMMyyyy}.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="30MB" />
<datePattern value="yyyyMMdd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n"/>
<!--<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] – %message%newline" />-->
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
</log4netConfiguration>
I have a Logger helper class as,
public static class Logger
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static log4net.ILog Log
{
get { return log; }
}
}
In my assembly info, I have this entry,
// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
log4net.config is the config file added to the web project.
In the code I log using the logger class,
Logger.Log.Info("User visits Sign In Page.");
Logging has been working when I set up the above setting. But suddenly logging has stopped working.
But when I created a new asp.net mvc website with above settings, logging works for that.
I tried with IIS Express and Local IIS. In both cases logging works for the test application I have created.
I cannot figure out why it's not logging? How can I diagnose this? What are the possible issues?
Solved by myself, reason was "for some reason" log4net configuration was not loaded from assembly info. Still I do not know why that happens.
I tried so many fixes proposed by different posts. Finally fixed the issue.
Solution mentioned in this post helped me to solve the issue.
I have added following configuration,
<!--These settings load the log4net configuration.-->
<add key="log4net.Config" value="log4net.config"/>
<add key="log4net.Config.Watch" value="True"/>
It starts logging!
Then I removed following line from assembly info,
// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
The reason is that Log4Net tries to load the config from the assembly that first uses LogManager.GetLogger(). If it's one of your class libraries it will simply ignore the attribute in all other assemblies.
The easiest way to fix it is to invoke LogManager in your start file (like Program.cs or Global.asax):
var logger = LogManager.GetLogger(typeof(Program));
logger.Info("Application started.");
//rest of app init.
Doing that will get you the expected behavior with the assembly attribute.
I found log4net won't load the webconfig configuration unless you call log4net.Config.XmlConfigurator.Configure(); on start up.
protected void Application_Start()
{
// your other codes
log4net.Config.XmlConfigurator.Configure(); // must have this line
Logger = log4net.LogManager.GetLogger(typeof(MvcApplication));
}
I had a similar issue: I would not get any logging output, when I ran my assembly from IIS or IISExpress.
However, none of the answers above worked for me.
In my case the solution was to specify the path to the config file as an absolute path. It turned out that IISExpress does not set the current directory to the bin folder and log4net would not find the config file, so I had to use this workaround:
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
// remove file:// part from uri
UriBuilder ub = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(ub.Path);
var fi = new FileInfo(Path.Combine(Path.GetDirectoryName(path), "Logging.config.xml"));
if (fi.Exists)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(fi);
var logger = log4net.LogManager.GetLogger(typeof(WebApiApplication));
logger.Info("Application started.");
}
else
{
throw new FileNotFoundException("log4net config file not found", fi.FullName);
}
Related
I have dotnetcore service which is running in Kubernetes. For logging, I have used the log4net. I am trying to send the logs of service to application-insights but the logs are not showing there.
I have added the below configuration in my service for application insights.
Runtime version: netcoreapp3.1 version-2.31.0.1
Hosting environment: Azure-cluster
app-service.csproj
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.16.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Log4NetAppender" Version="2.16.0" />
...
<ItemGroup>
log4net.config
...
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<InstrumentationKey name="AppInsightsKey" value="abcdefgh-abcd-abcd-abcd-abcdefghijkl" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline"/>
</layout>
</appender>
startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
Logger.ConfigureLog4Net("./logs/app.log", Configuration)
...
}
public void ConfigureServices(IServiceCollection services)
{
// The following line enables Application Insights telemetry collection.
services.AddApplicationInsightsTelemetry();
services.AddSingleton<ITelemetryInitializer, CloudRoleNameTelemetryInitializer>();
// This code adds other services for the application.
services.AddMvc();
...
}
CloudRoleNameTelemetryInitializer.cs
using System.Net;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
public class CloudRoleNameTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
// set custom role name here
telemetry.Context.Cloud.RoleName = "app-service";
}
}
I have also added the APPINSIGHTS_INSTRUMENTATIONKEY environment variable for service. I am able to see the request information for service but not logs. Only 2 logs are showing in the log section of application-insights but it is not from the application(log4net).
No XML encryptor configured. Key {XXX-XXX-XXX-XXX-XXX} may be persisted to storage in unencrypted form.
Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when the container is destroyed.
Below are some links I have explored.
https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-trace-logs
https://medium.com/#muralimohan.mothupally/application-insights-integration-with-log4net-e1bef68fe3c8
https://blog.ehn.nu/2014/11/using-log4net-for-application-insights/
https://jan-v.nl/post/using-application-insights-in-your-log4net-application/
But still, logs are not adding in the application insights. Is there anything I am missing here? Also is it possible to add Console.WriteLine logs to application-insights as like in nodejs app we can send it by enabling the application-insights module's configuration? Can you please help me?
Thanks...
Thanks for Peter Drier's answer, I thinks below code he provided is useful to you.
For more details, you can refer the orgin post.
Log4Net and Application Insights-no data is coming through
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
<threshold value="INFO" />
<InstrumentationKey value="12345678-7946-1234-1234-8b330fbe1234" />
</appender>
I'm just trying to ship some error logs from my ASP.NET MVC 5 app to Logz.io
I'm using NLog to ship my logs.
I've installed NLog and NLog.Web packages
I have the following nlog.config file :
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
throwExceptions="true"
internalLogLevel="ERROR"
internalLogFile="C:\Temp\nlog-internal.log">
<extensions>
<add assembly="Logzio.DotNet.NLog"/>
</extensions>
<targets async="true">
<target name="file" type="File"
fileName="<pathToFileName>"
archiveFileName="<pathToArchiveFileName>"
keepFileOpen="false"
layout="<long layout patten>"/>
<target name="logzio"
type="Logzio"
token="LRK......"
logzioType="nlog"
listenerUrl="https://listener.logz.io:8071"
bufferSize="1"
bufferTimeout="00:00:05"
retriesMaxAttempts="3"
retriesInterval="00:00:02"
debug="false" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="logzio" />
</rules>
</nlog>
Then, each of my C# controller have this line :
private static Logger logger = LogManager.GetCurrentClassLogger();
and then I try to ship my logs using something like :
logger.Fatal("Something bad happens");
However, when I writeTo="file" in the nlog.config file, I can find a log file on my local disk with "Something bad happens", so everything is fine.
However, nothing appear on my LogzIo web interface when I writeTo="logzio", no logs are shipped there.
What did I miss ?
Answering my own question after I found how to solve this.
Actually, my whole project use HTTPS.
In internal Nlog logs, I had this error
Error : System.Net.WebException : The request was aborted: Could not create SSL/TLS secure channel
I've just added this line of code at the very beginning of ApplicationStart in Global.asax.cs
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
After testing the whole project during some days, it seems it doesn't affect the other parts of the project.
However, just be careful as it is a global setting
I had the same issue, and it turned out that in my published app the logzio dlls were missing. I added them and it resolved the issue.
Check if you're missing these files in your bin folder:
Logzio.DotNet.NLog.dll
Logzio.DotNet.Core.dll
I have followed many different guides on how to configure the log4net, it is up and running but i can't find a log file anywhere ...
This is how my configuration look like:
Web.Config
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\\temp\\Log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
Global.asax:
XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
//XmlConfigurator.Configure();
StartUp.cs
//[assembly: XmlConfigurator(ConfigFile = "Web.config", Watch = true)]
[assembly: XmlConfigurator(Watch = true)]
Declaration
readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
Logging
BasicConfigurator.Configure();
logger.Info("Info logging ...");
logger.Error("Homepage loading test logging ...");
Where my file value is: <file value="C:\\temp\\Log.txt" />
I have tried several paths, and commented out what above but no success.
What am i doing wrong?
UPDATE:
As suggested by John H i have tried configuring and calling the logger in the Application_Start method and tried several alternative configs with it but with no luck. Here are 2 screenshots of some debugging info:
Main properties:
Below are the Logger properties:
What am i doing wrong?
OK so i got it to work following this tutorial: log4net-guide-dotnet-logging
I have created a log4net.config file with content as showed in tutorial.
used [assembly: XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
Called it like this:
ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
logger.Info("Application started.");
file is created and content logged as well.
I am gonna compare the config files content and see if the difference is in there and go gradually comparing everything till i have found what caused it not to work.
Thank you for helping me!
Kind regards
From your screenshots, we can see that your logger is not being initialised with your configuration, because IsDebug is false. One thing I notice from your screenshot, is you're trying to pass the path to Web.config directly to the Configure() method. I realise that may be an attempt to solve the problem, so you may have already tried my next suggestion, but calling Configure() in the manner you currently have won't work because Web.config is not published to your bin\debug folder. It will called Web.projectname.config. Calling
XmlConfigurator.Configure()
with no parameters, will automatically resolve the correct configuration file in your output directory. I'm guessing you've tried that, but if that still doesn't work, try this as well:
using log4net;
protected void Application_Start(object sender, EventArgs e)
{
// Initialising configuration before requesting a logger.
XmlConfigurator.Configure();
// Requesting a logger only after the configuration has been initialised.
var logger = LogManager.GetLogger(typeof(Global));
logger.Info("Application started.");
}
I'm not sure it will make any difference, but your configuration looks fine to me.
But by inspecting the IsDebug property on the logger, you'll at least be able to tell if the configuration has even been read.
Edit: One other thing, make sure the application will have the permissions to write to the file. From the documentation:
The RollingFileAppender extends the FileAppender and has the same behavior when opening the log file. The appender will first try to open the file for writing when ActivateOptions() is called. This will typically be during configuration. If the file cannot be opened for writing the appender will attempt to open the file again each time a message is logged to the appender. If the file cannot be opened for writing when a message is logged then the message will be discarded by this appender.
I am trying to setup Serilog in a CMS that has some default logging configuration setup that we define as the CMS, however allowing developers using the CMS to extend and configure there own logging requirements by using the Serilog AppSettings Nuget package - https://github.com/serilog/serilog-settings-appsettings
I have some of this working and able to configure other Sinks in an external configuration file the problem I have and need help with, is how do I let developers configure a file sink to generate a txt logile that only includes their namespace?
With a C# class I know I can create a sub-logger and then use a Filter like so
.Filter.ByIncludingOnly(Matching.FromSource("DevelopersNamespace")) but using the Serilog Analyzer VS Extension - https://github.com/Suchiman/SerilogAnalyzer it cannot generate an example XML AppSettings configuration.
Here is a copy of my Logger Configuration in C#
Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));
//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log-{Date}.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
.Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
.Enrich.With<Log4NetLevelMapperEnricher>()
//Main .txt logfile - in similar format to older Log4Net output
//Ends with ..txt as Date is inserted before file extension substring
.WriteTo.File($#"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: LogEventLevel.Debug,
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}")
//.clef format (Compact log event format, that can be imported into local SEQ & will make searching/filtering logs easier)
//Ends with ..txt as Date is inserted before file extension substring
.WriteTo.File(new CompactJsonFormatter(), $#"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..json",
rollingInterval: RollingInterval.Day, //Create a new JSON file every day
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
restrictedToMinimumLevel: LogEventLevel.Debug)
//Read any custom user configuration of logging from serilog config file
.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + #"\config\serilog.config")
.CreateLogger();
Here is an example of the AppSettings configuration file that users will be able to modify their own sinks with.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- Controls log levels for all sinks (Set this higher than child sinks) -->
<add key="serilog:minimum-level" value="Verbose" />
<!-- Write to a user log file -->
<add key="serilog:using:File" value="Serilog.Sinks.File" />
<add key="serilog:write-to:File.path" value="%BASEDIR%\logs\warren-log.txt" /><!-- Can we do a relative path to website ? -->
<add key="serilog:write-to:File.restrictedToMinimumLevel" value="Debug" />
<add key="serilog:write-to:File.retainedFileCountLimit" value="32" /> <!-- Number of log files to keep (or remove value to keep all files) -->
<add key="serilog:write-to:File.rollingInterval" value="Day" /> <!-- Create a new log file every Minute/Hour/Day/Month/Year/infinite -->
<!-- TODO: How do I filter the file sink for customer to their own namespace ?? -->
</appSettings>
</configuration>
I am open to ideas and suggestions on how I can achieve this with a goal of allowing developers to configure their own sinks and to optionally filter to their own namespace if they wish to (as I doubt users will want to write their own sink code)
For anyone interested or was to come across this post at a later date this is how I solved it.
I used two configuration files one to configure the main logging pipeline and a user config for a sub-logger that they can then use filtering if required without effecting the main logging pipeline.
Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));
//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
.Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
.Enrich.With<Log4NetLevelMapperEnricher>()
//Main .txt logfile - in similar format to older Log4Net output
//Ends with ..txt as Date is inserted before file extension substring
.WriteTo.File($#"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: LogEventLevel.Verbose,
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}")
//.clef format (Compact log event format, that can be imported into local SEQ & will make searching/filtering logs easier)
//Ends with ..txt as Date is inserted before file extension substring
.WriteTo.File(new CompactJsonFormatter(), $#"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..json",
rollingInterval: RollingInterval.Day, //Create a new JSON file every day
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
restrictedToMinimumLevel: LogEventLevel.Verbose)
//Read from main serilog.config file
.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + #"\config\serilog.config")
//A nested logger - where any user configured sinks via config can not effect the main 'umbraco' logger above
.WriteTo.Logger(cfg =>
cfg.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + #"\config\serilog.user.config"))
.CreateLogger();
Here is then a sample of the two configuration files:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- Used to toggle the loge levels for the main Umbraco log files -->
<!-- Found at /app_data/logs/ -->
<!-- NOTE: Changing this will also flow down into serilog.user.config -->
<add key="serilog:minimum-level" value="Verbose" />
<!-- To write to new log locations (aka Sinks) such as your own .txt files, ELMAH.io, Elastic, SEQ -->
<!-- Please use the serilog.user.config file to configure your own logging needs -->
</appSettings>
</configuration>
And here is the configuration file where the user can then filter with their own namespace:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- Controls log levels for all user-definied child sub-logger sinks configured here (Set this higher than child sinks) -->
<add key="serilog:minimum-level" value="Verbose" />
<!-- For Different Namespaces - Set different logging levels -->
<add key="serilog:minimum-level:override:Microsoft" value="Warning" />
<add key="serilog:minimum-level:override:Microsoft.AspNetCore.Mvc" value="Error" />
<add key="serilog:minimum-level:override:YourNameSpace" value="Information" />
<!-- All logs definied via user.config will contain this property (won't be in main Umbraco logs) -->
<add key="serilog:enrich:with-property:websiteName" value="Warrens Website" />
<!-- Write to a user log file -->
<add key="serilog:using:File" value="Serilog.Sinks.File" />
<add key="serilog:write-to:File.path" value="%BASEDIR%\logs\warren-log.txt" />
<add key="serilog:write-to:File.restrictedToMinimumLevel" value="Debug" /> <!-- I will be ignored as Debug as the user logging pipleine has it min set to Information, so only Info will flow through me -->
<add key="serilog:write-to:File.retainedFileCountLimit" value="32" /> <!-- Number of log files to keep (or remove value to keep all files) -->
<add key="serilog:write-to:File.rollingInterval" value="Day" /> <!-- Create a new log file every Minute/Hour/Day/Month/Year/infinite -->
<!-- Filters all above sink's to use this expression -->
<!-- Common use case is to include SourceType starting with your own namespace -->
<add key="serilog:using:FilterExpressions" value="Serilog.Filters.Expressions" />
<add key="serilog:filter:ByIncluding.expression" value="StartsWith(SourceContext, 'MyNamespace')" />
</appSettings>
</configuration>
We have a multi-tenanted MVC app, meaning that exactly the same app is published to multiple IIS virtual directories / applications, and then the app its self works out who it is, and skins its self (css) accordingly.
This is all very well, but anything logged by ELMAH in our elmah database gets logged under the same applicationName, as this is pulled out of Web.Config elmah section below where everything would be logged as "MyappName" :
<configuration>
[...]
<elmah>
<security allowRemoteAccess="false" />
<errorLog
type="Elmah.SqlErrorLog, Elmah"
connectionStringName="elmah"
applicationName="MyappName" />
</elmah>
</configuration>
The question is therefore how to override the applicationName setting from web.config with something specific so we can distinguish errors for a given tenant web site.
As this is configurable within the web.config, ELMAH are already providing you with a way to specify the application name when the application is deployed to different locations - it's just a case of making use of it.
This would generally be something that you would manipulate as part of your deployment steps. If you are doing it manually then it's going to be a pain, but it could be easily manipulated by using a web.config transform.
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<elmah>
<errorLog applicationName="MyappName" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</elmah>
</configuration>
I wonder if the following might work, if you put the following into your Global.asax:
var service = ServiceCenter.Current;
ServiceCenter.Current = context =>
{
var connectionString = "YOUR CONNECTION STRING";
var container = new ServiceContainer(service(context));
var log = new SqlErrorLog(connectionString) { ApplicationName = "APP NAME HERE" };
container.AddService(typeof(ErrorLog), log);
return container;
};