How can I stop NLog from double logging - c#

I'm writing a WEB API call for NLog, so remote apps can log to my logging table.
In my controller I have (hard-coded for now as a sanity check):
NLogger.LogError("Some Error Message", "An exception", 5, "A computer name");
Then my static LogError method looks like this (I tried LogEventInfo() too):
public static void LogError(string msg, string ex, int appid, string machineName)
{
LogEventInfo logEvent = new LogEventInfo(LogLevel.Error, "Api Logger", "Another test msg");
logEvent.Properties["myMsg"] = msg;
logEvent.Properties["myEx"] = ex;
logEvent.Properties["myAppId"] = appid;
logEvent.Properties["myMachineName"] = machineName;
NLogManager.Instance.Log(logEvent);
}
Lastly, this is my code first config for that rule (there's 2 others with different db targets):
private static void ConfigureApiLog()
{
var dbApiErrorTarget = new DatabaseTarget
{
ConnectionString = ConnectionFactory.GetSqlConnection().ConnectionString,
CommandText = "usp_LogError",
CommandType = CommandType.StoredProcedure
};
dbApiErrorTarget.Parameters.Add(new DatabaseParameterInfo("#level",
new global::NLog.Layouts.SimpleLayout("${level}")));
dbApiErrorTarget.Parameters.Add(new DatabaseParameterInfo("#logger",
new global::NLog.Layouts.SimpleLayout("${logger}")));
dbApiErrorTarget.Parameters.Add(new DatabaseParameterInfo("#message",
new global::NLog.Layouts.SimpleLayout("${event-properties:item=myMsg}")));
dbApiErrorTarget.Parameters.Add(new DatabaseParameterInfo("#exception",
new global::NLog.Layouts.SimpleLayout("${event-properties:item=myEx}")));
dbApiErrorTarget.Parameters.Add(new DatabaseParameterInfo("#AppId",
new global::NLog.Layouts.SimpleLayout("${event-properties:item=myAppId}")));
dbApiErrorTarget.Parameters.Add(new DatabaseParameterInfo("#MachineName",
new global::NLog.Layouts.SimpleLayout("${event-properties:item=myMachineName}")));
Config.AddTarget("database", dbApiErrorTarget);
Config.LoggingRules.Add(new LoggingRule("*", LogLevel.Error, LogLevel.Fatal, dbApiErrorTarget));
}
I expect 1 log per log call to the logger instance, but I'm getting two and I'm not exactly sure why:
Id Date Level Logger Message Exception AppId MachineName
1 2017-03-03 22:43:20.557 Error Api Logger Another test msg 0 mylocalmachine
2 2017-03-03 22:43:20.603 Error Api Logger Some Error Message An exception 5 A computer name
AppId 0 is my Api, 5 is some remote app, hard coded at this point as POC.
Might be that it's Friday, but I can't seem to figure out what's wrong with the code. Any help would be appreciated!

I had this problem and found the problem, for my specific case. Problem was double entries everywhere on every target.
I had a .NET Core web application which used the UseNLog() inside the Program.cs IWebHostBuilder. This performs AddNLog() internally.
Then in the startup I manually did loggerInstance.AddNLog() which caused the dual insertion.
The latter must be removed since UseNLog is a far better and "sooner" time to enable NLog
Hope it helps!

Rules in NLog can be target specific, or it can write to all targets. The default rule(s) won't have any targets specified, so they will write to any you create. You're also adding your own rule, which writes specifically to your target and no others.
Thus, the double-logging.
You can remove the default rules to resolve the issue.
Config.LoggingRules.Clear();
before you add your rule.

Related

Making a security definition request to FIX adapter

I am trying to make a request (Security Definition Request) to FIX Adapter using the following method. This is an application level call and I manually invoke this method whenever there is a successful connection to FIX Adapter.
WHen i run this method i get a "Field not found for tag:49" exception message. However SecurityDefinitionRequest class doesnt allow me to set Tag 49 (SenderCompId) to it.
First of all is this the right way to make a SecurityDefinitionRequest? I tried looking at QuickFix/N docs but they dont explain how to make such request.
http://quickfixn.org/tutorial/sending-messages.html
Infact i havent seen any articles so far in the internet. Any suggestions?
public void ToApp(Message message, SessionID sessionId)
{
var request =
new SecurityDefinitionRequest()
{
SecurityReqID = new SecurityReqID("1"),
SecurityID = new SecurityID("5"),
SecurityRequestType = new SecurityRequestType(3),
SecurityType = new SecurityType("FUT")
};
request.SetField(new SenderCompID("217"));
Session.SendToTarget(request);
}
The constructed message looks like this
8=FIX.4.29=3735=c48=549=217167=FUT320=1321=310=003
I'm going to suggest:
SessionId currentSessionId = new QuickFix.SessionID("FIX4.2", "217","CBOE");
securityDefinitionRequest.SetSessionID(currentSessionId );

Activation error occured while trying to get instance of type Database, error occurring only when connection string is created dynamically

I have a piece of code (.NET Framework 4.5.2, Enterprise Library 5.0.505.0) where I need to connect to a SQL Server database. However, the DB name may keep changing depending on user's requirement. So, I have the following piece of code to write the connection string dynamically to the app.config file.
public void CreateNewConnectionStringInConfig(string initialCatalog)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = ConfigurationManager.AppSettings["Data Source"];
builder.PersistSecurityInfo = true;
builder.InitialCatalog = initialCatalog; //This is the DB name
builder.UserID = ConfigurationManager.AppSettings["User ID"];
builder.Password = ConfigurationManager.AppSettings["Password"];
// Get the application configuration file.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Create a connection string element.
ConnectionStringSettings csSettings = new ConnectionStringSettings("UserSelectedConnectionString", builder.ConnectionString, "System.Data.SqlClient");
// Get the connection strings section.
ConnectionStringsSection csSection = config.ConnectionStrings;
// Add the new element.
csSection.ConnectionStrings.Add(csSettings);
// Save the configuration file.
config.Save(ConfigurationSaveMode.Modified);
// Refresh the section so the new configuration can be re-read
ConfigurationManager.RefreshSection("connectionStrings");
}
I checked and the connection string is getting created fine in the vshost.exe.Config file while debugging. However, when I am trying to create the Database object, I am getting an error. The code used to create the DB object is as shown below.
public class MyDac
{
private readonly Database _db;
public MyDac()
{
DatabaseProviderFactory factory = new DatabaseProviderFactory();
_db = factory.Create("UserSelectedConnectionString");
}
}
I am getting the following error while trying to create the _db object.
Activation error occured while trying to get instance of type Database, key "UserSelectedConnectionString"
Microsoft.Practices.ServiceLocation.ActivationException: Activation error occured while trying to get instance of type Database, key "UserSelectedConnectionString" ---> Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Data.Database", name = "UserSelectedConnectionString".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type Database does not have an accessible constructor.
Things that I have tried:
1) Upgrading the Enterprise Library version to 6.0.0.0 resolves the issue but that is not an option for me. I have to keep it to version 5.0.505.0.
2) When I hard code the connection string in the App.config file from before hand (rather than writing it during run time), the app works fine. However, I can't do that in real life because the database name will keep on changing.
Any help will be much appreciated. Thanks!
I changed my code as shown below and that started working. However, I do not have any explanation for it:
public class MyDac
{
private readonly Database _db;
public MyDac()
{
_db = new SqlDatabase("UserSelectedConnectionString");
}
}

Different connection string for output or trigger

Here i have a webjob function using servicebus triggers and outputs. I'd like to set a different configuration for output and input.
public static void OnPush(
[ServiceBusTrigger("%PushProcessor.InputTopicName%", "%PushProcessor.InputTopicSubscriptionName%", AccessRights.Listen)]
BrokeredMessage message,
[ServiceBus("%PushProcessor.OutputTopicName%", AccessRights.Send)]
out BrokeredMessage output
)
I see in latest api that one can control the job host with service bus extensions.
JobHostConfiguration config = new JobHostConfiguration
{
StorageConnectionString = ConfigHelpers.GetConfigValue("AzureWebJobsStorage"),
DashboardConnectionString = ConfigHelpers.GetConfigValue("AzureWebJobsDashboard"),
NameResolver = new ByAppSettingsNameResolver()
};
config.UseServiceBus(new ServiceBusConfiguration
{
MessageOptions = new OnMessageOptions {
MaxConcurrentCalls = 2,
AutoRenewTimeout = TimeSpan.FromMinutes(1),
AutoComplete = true,
},
ConnectionString = ConfigHelpers.GetConfigValue("InputServiceBusConnectionString"),
});
Unfortunately i see no control for the connection string for the output. I'd like a different connection string (different namespace/access rights) to be used for inputs versus outputs.
Perhaps the api can support registering named jobhostconfigurations to a jobhost, and referring to that name in the attributes for the trigger/output. Anyways if there is a way to do this let me know.
Yes, also in the latest beta1 release you'll see that there is now a ServiceBusAccountAttribute that you can apply along with the ServiceBusTrigger/ServiceBus attributes. For example:
public static void Test(
[ServiceBusTriggerAttribute("test"),
ServiceBusAccount("testaccount")] BrokeredMessage message)
{
. . .
}
We've done the same for all the other attribute types (Queue/Blob/Table) via StorageAccountAttribute. These account attributes can be applied at the class/method/parameter level. Please give this new feature a try and let us know how it works for you. Also, see the release notes for more details.

NLog filter by LogLevel as MappedDiagnosticsContext

Based on the answer here: How Thread-Safe is NLog? I have created a Logger and added two MappedDiagnosticsContext to NLog:
NLog.MappedDiagnosticsContext.Set("Module", string.Format("{0}.{1}", module.ComputerName, module.ModuleType));
NLog.MappedDiagnosticsContext.Set("ModuleCoreLogLevel", string.Format("LogLevel.{0}", module.CoreLogLevel));
I can successfully use the "Module" Context in the NLog config (programmatically) to generate the file name the logger should log to:
${{when:when=length('${{mdc:Module}}') == 0:inner=UNSPECIFIED}}${{when:when=length('${{mdc:Module}}') > 0:inner=${{mdc:Module}}}}.txt
This logs e.g. all messages with a "Module" context of "Test" to a filename called Module.txt
I now want to be able to set the LogLevel for the different Modules using this way, and only Log messages which correspond to this LogLevel (or higher)
I am trying to do this through filters, this means, on the LoggingRule I am trying to add a filter:
rule92.Filters.Add(new ConditionBasedFilter { Condition = "(level < '${mdc:ModuleCoreLogLevel}')", Action = FilterResult.IgnoreFinal });
This however does not seem to filter messages.
If I have for example a message which is emitted using Logger.Trace(), and the LogLevel on "ModuleCoreLogLevel" is set to LogLevel.Debug, I can still the Message in the resulting LogFile.
I solved this by doing this for each level:
rule92.Filters.Add(new ConditionBasedFilter { Condition = "(equals('${mdc:ModuleCoreLogLevel}', 'LogLevel.Trace') and level < LogLevel.Trace)", Action = FilterResult.IgnoreFinal });

Enterprise library 4.1 logging error?

I am using Enterprise library 4.1 logging. I am getting compile error at 'EnterpriseLibraryContainer'. EnterpriseLibraryContainer doesn't work for 4.1 version?
public LogWriter defaultWriter;
public Logging()
{
// Resolve the default LogWriter object from the container.
// The actual concrete type is determined by the configuration settings.
defaultWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
}
[Description("Logging to EverViewer and RollingFile with Write method of a LogWriter")]
public void LogWriter(string message, string title, EventLogEntryType eventType)
{
// Check if logging is enabled before creating log entries.
if (defaultWriter.IsLoggingEnabled())
{
// Create a string array (or List<>) containing the categories.
string[] logCategories = new string[] { "General" };
LogEntry logEntry = new LogEntry();
logEntry.Message = message;
logEntry.Categories = logCategories;
logEntry.Priority = 10;
logEntry.EventId = 9005;
logEntry.Severity = ConvertEventType(eventType);
logEntry.Title = title;
defaultWriter.Write(logEntry);
}
}
EnterpriseLibraryContainer was introduced with Enterprise Library 5 so is not available with Enterprise Library 4.1.
Try replacing that code with the following to get the default writer:
public Logging()
{
// Resolve the default LogWriter object from the container.
// The actual concrete type is determined by the configuration settings.
defaultWriter = new LogWriterFactory().Create();
}
Are you by any chance targeting the .NET 4 Client Profile instead of the full .NET 4?

Categories

Resources