NLog throws an error when loading an XmlLayout configuration file - nlog

I am attempting to configure NLog to output error logs in an XML format, however, NLog is not properly loading the configuration.
Here is the LAYOUT portion of my configuration:
<layout xsi:type="XmlLayout" includeAllProperties="true" propertiesElementKeyAttribute="" propertiesElementName="{0}" elementName="errorlog">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}" />
<element name="processname" value="${processname}" />
<element name="logger" value="${logger}" />
<element name="message" value="${message}" />
</layout>
When calling the LogManager.GetCurrentClassLogger() method, the following error is generated:
Parameter name not supported on XmlLayout
Here are the additional details captured in the NLog error log file:
2019-03-04 16:25:39.9645 Trace Scanning Property Renderers 'System.Collections.ObjectModel.ReadOnlyCollection`1[NLog.LayoutRenderers.LayoutRenderer]' System.Collections.ObjectModel
2019-03-04 16:25:39.9645 Trace Scanning LevelLayoutRenderer 'Layout Renderer: ${level}'
2019-03-04 16:25:39.9645 Debug Setting 'XmlLayout.name' to 'processname'
2019-03-04 16:25:39.9835 Warn Error when setting 'processname' on attibute 'name' Exception: System.NotSupportedException: Parameter name not supported on XmlLayout
at NLog.Internal.PropertyHelper.SetPropertyFromString(Object obj, String propertyName, String value, ConfigurationItemFactory configurationItemFactory)
at NLog.Config.LoggingConfigurationParser.ConfigureObjectFromAttributes(Object targetObject, ILoggingConfigurationElement element, Boolean ignoreType)
2019-03-04 16:25:39.9835 Error Parsing configuration from C:\Users\<user>\Documents\Visual Studio 2017\Projects\TestingNlog\TestingNlog\bin\Debug\NLog.config failed. Exception: NLog.NLogConfigurationException: Exception when parsing C:\Users\<user>\Documents\Visual Studio 2017\Projects\TestingNlog\TestingNlog\bin\Debug\NLog.config. ---> System.NotSupportedException: Parameter name not supported on XmlLayout
If I remove the ELEMENT tags from the configuration file, I am able to generate a partial log file with just the single XML element ERRORLOG with the 2 specified attributes. However, I have not found a way to include the ELEMENT tags in my output log files.
NLog.dll - v4.6.0.9068
C# .NET - v4.7.2
Any ideas or assistance would be greatly appreciated!
-Kasey911

Snakefoot is correct,
this has been changed after NLog 4.6 RC 1
In NLog 4.6 RC 1
<layout xsi:type="XmlLayout" elementName='logevent'>
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<element elementName="message" elementValue="${message}" />
</layout>
In NLog 4.6 RC 2 (not released yet), and probably RTM
<layout xsi:type="XmlLayout" elementName='logevent'>
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<element name="message" value="${message}" />
</layout>

Related

Log4Net - make smtp appender send email only after 100 errors

I would like to send an email only after 100 ERRORS were written as a html table(That's the purpose of the SmtpExtendedAppender, iterate over all the messages that were saved) but I am not sure how to access them.
This is my app.config:
<appender name="SmtpAppender" type="log4net.Appender.SmtpExtendedAppender">
<authentication value="Basic" />
<password value="xxxxxx"/>
<username value="xxxxxxxx"/>
<from value="myemail#gmail.com" />
<to value="toemail#gmail.com" />
<smtpHost value="smtp.gmail.com" />
<isBodyHtml value="true" />
<bufferSize value="100" />
<EnableSsl value="true"/>
<subject value="test logging message" />
<lossy value="true" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="WARN"/>
</evaluator>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{ABSOLUTE} [%logger]%newlineUsername: %property{username}%newline%level - %message%newline%exception" />
</layout>
</appender>
This is my console application:
static void Main(string[] args)
{
Console.WriteLine("hello world");
log.Error("This is my first error message");
log.Error("This is my second error message");
Console.ReadLine();
}
I am not fully understand how the log4net buffer size works, even though I gave it a value of 100, it sends me 2 separated emails every time I run my console application.
If I will run this application 50 times to get to 100 ERRORS, would it be possible to accumulate them and then send them in one email?
No that is not possible. The appender works not over multiple instances of your application. Every time you restart your application, all buffers are empty.

Using log4net to log unhandled errors when using OWIN

Can you point me to some log4net tutorial or samples that logs all unhandled exceptions occurring on my MVC Web Api when using OWIN?
I have a Startup class that configures Castle Windsor and OAuth and I'm not sure how application errors are handled for OWIN enabled applications.
I have tried putting the log4net code in the Application_Error event in global.asax but it never gets executed.
public class WebApiApplication : System.Web.HttpApplication {
protected void Application_Start() {
log4net.Config.XmlConfigurator.Configure();
}
protected void Application_Error(object sender,EventArgs e) {
Exception lastException = Server.GetLastError();
var logger = log4net.LogManager.GetLogger(typeof(WebApiApplication));
logger.Fatal(lastException);
}
}
Any ideas why this is?
EDIT: web.config with log4net configuration:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<logger name="SiteWorksAPI">
<level value="Debug" />
<appender-ref ref="EventLogAppender" />
</logger>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="C:\ProgramData\Site\SiteWorksAPILog.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<immediateFlush value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="============================================================%nLogger = %logger.%nLocation = %location.%nUnique Token = %property{x-fcc-uniquetoken}.%nDate = %date{dd MMM yyyy - HH:mm:ss}.%nMessage = %message%n" />
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<applicationName value="SiteWorks.API" />
<logname value="SiteWorks API Log" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="Date: %date{dd MMM yyyy - HH:mm:ss} %nMessage: %message %nIdentity: %identity %nUnique Token: %property{x-fcc-uniquetoken} %nChange Time Stamp: %property{x-fcc-changedatetime} %nOriginal Time Stamp: %property{x-fcc-originaltimestamp} %nOriginating System: %property{x-fcc-originatingsystem} %nOriginating User: %property{x-fcc-originatingusername} %nRequest Uri: %property{Request} %nResponse Headers: %property{ResponseHeaders}%nLogger: %logger %nThread: %thread %n%n%exception" />
</layout>
</appender>
</log4net>
You're not seeing any log events because you haven't defined a root logger in your config - the only logger you've defined is called SiteWorksAPI so any loggers you create with any other name - for example, the one named after typeof(WebApiApplication) - will not log anything. If you add a breakpoint on the logging statement you'll see that all log levels are disabled.
The appenders defined in a root logger are inherited by all named appenders (unless the child appenders are defined with additivity = false) - but child appenders set their own log level.
<root>
<level value="Debug" />
<appender-ref ref="EventLogAppender" />
</root>
Edit: there's also another thing to consider - your defined logger only uses the EventLogAppender - note that in order to log to the Event Log, the documentation states EventLogAppender will fail if you try to write using an event source that doesn't exist unless it is running with local administrator privileges but the event source needs to be created by an elevated process.
For testing purposes, you might want to add your FileAppender to the logger.

SSRS using Business Development Studio and FetchXML

I have the following Fetchxml for a Custom report to get all the Active Leads:
<fetch distinct="false" mapping="logical" output-format="xml-platform" version="1.0">
<entity name="lead" >
<attribute name="companyname" />
<attribute name="leadid" />
<attribute name="gr_totaltraveldays" />
<attribute name="gr_marketvertical" />
<attribute name="leadsourcecode" />
<attribute name="lastname" />
<attribute name="firstname" />
<attribute name="estimatedamount" />
<attribute name="gr_dayssincelastactivity" />
<attribute name="new_numberofattendees" />
<attribute name="ownerid" />
<order descending="false" attribute="ownerid" />
<filter type="and" >
<condition attribute="statecode" value="0" operator="eq" />
</filter>
</entity>
I got this FetchXML from Advance Find in CRM 2011.
When i use this FetchXML in my report DataSet I get below error:
The gr_totaltraveldays field is there. I looked into the Database for fields and this field is in LeadExtensionBase table.
i had the same problem in BIDS with FetchXML.i was getting the error : "The attribute "XXXX" cannot be found for entity "XX". Specify a valid query, and try again." However, the field existed in the entity and was published.
The solution was to change the connection string, adding the organization name, in the Datasource as following: {URL};{organizationName};
then it worked!
for example : https://XXXX.crm4.dynamics.com;org12345ab;
You can find the organizationname in the Settings --> Customization --> Deveoper resources.
Regards!
Check your connection string. I had the same problem with my report.Seems like your connection string is explicitly pointing to the right organisation.
https://aaaa.crm4.dynamics.com;
This should work

AdoNetAppender and Clob field

I have a asp.net 3.5 app that is using log4Net and AdoNetAppender. Currently the app uses a message field just like the log4net documentation http://logging.apache.org/log4net/release/config-examples.html. I would like to convert the field from varchar2 to Clob. I was trying to find some documentation on how to do this. All I could find is:
http://old.nabble.com/DbType-for-CLOB-column-using-AdoNetAppender-td1214036.html#a1214036
which wasn't too useful. Does anyone know a link or some samples on how to use a Clob file with a AdoNetAppender?
Thanks, Bill N
Did you try this:
http://marc.info/?l=log4net-user&m=110874200319166
basically you need to set the DbType to string and remove the Size parameter. Apparently this does not work correctly for nvarchar(max) (see here) but that does not mean it will not work for Clob.
I know this is an old question, but I recently needed to pass a CLOB parameter to a package procedure, using log4net. I was not able to do that using the suggestions I found online, including the one with setting the DbType to String and removing Size.
I am using an Oracle package procedure that takes a parameter of type CLOB. Using a custom AdoNetAppenderParameter I am able to pass long strings (270k+ characters) to the procedure and store them in the DB (Oracle 9i).
First of all, I had to use Oracle's Data Access Provider (after all, Microsoft's System.Data.OracleClient has been deprecated). Your project must reference Oracle.DataAccess.dll. I got the NuGet package by searching for "oracle.dataaccess" in NuGet package manager.
The library has an implementation of DbParameter, OracleParameter, that has a OracleDbType property. The type of the property is OracleDbType which is an enumeration that has the Clob value.
After adding the reference, I changed the appender's connection type to:
<connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
I then created a custom AdoNetAppenderParameter that creates a new OracleParameter and sets its type to Clob:
public class OracleAdoNetAppenderParameter : AdoNetAppenderParameter
{
public OracleDbType OracleDbType { get; set; }
public override void Prepare(System.Data.IDbCommand command)
{
if (!(command is OracleCommand))
{
string message = string.Format("The log4net parameter of type {0} can only be used with an appender connection of type {1}. The expected command type, {2}, cannot be supplied. Please check the parent appender's connectionType property.",
this.GetType(), typeof(OracleConnection), typeof(OracleCommand));
throw new System.ArgumentException(message, "command");
}
var parameter = command.CreateParameter() as OracleParameter;
parameter.ParameterName = base.ParameterName;
parameter.OracleDbType = this.OracleDbType;
command.Parameters.Add(parameter);
}
}
I exposed a property, OracleDbType, so I would be able to specify it through configuration.
I initially did not expose the property, named the class OracleClobAdoNetAppenderParameter and set the OracleDbType property to Clob inside the Prepare method.
After I created the class, I added the parameter to the appender's configuration, like this:
<parameter type="YourNamespace.OracleAdoNetAppenderParameter, YourAssembly">
<OracleDbType value="Clob" />
<parameterName value=":yourProcedureClobParam"/>
<layout type="..."></layout>
</parameter>
You can use your own layout. I am passing my large string through log4net's context as a custom parameter.
Here's the final configuration I'm using:
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
<connectionString value="data source=xxx;User ID=xxx;Password=xxx"/>
<commandText value="MY_PKG.LogMessage"/>
<commandType value="StoredProcedure" />
<!-- SERVICE_MESSAGE -->
<parameter type="MyNamespace.OracleAdoNetAppenderParameter, MyAssembly">
<OracleDbType value="Clob" />
<parameterName value=":service_message"/>
<layout type="log4net.Layout.RawPropertyLayout">
<key value="service_message"/>
</layout>
</parameter>
<!-- LOG_LEVEL -->
<parameter>
<parameterName value=":type"/>
<dbType value="String"/>
<size value="20"/>
<layout type="log4net.Layout.PatternLayout" value="%level"/>
</parameter>
<!-- LOG_DATE -->
<parameter>
<parameterName value=":timestamp"/>
<dbType value="DateTime"/>
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<!-- MESSAGE -->
<parameter>
<parameterName value=":message"/>
<dbType value="String"/>
<size value="1000"/>
<layout type="log4net.Layout.PatternLayout" value="%message"/>
</parameter>
<!-- EXCEPTION -->
<parameter>
<parameterName value=":error"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
......
</appender>
Hope it helps.

Default values for AdoNetAppender parameter

I am using log4net with AdoNetAppender. It logs all log info into a table. This table actually has 2 Integer columns (can be null).
Here is the relevant part of my log4net config:
<commandText value="INSERT INTO ActivityLog ([Date],[Thread],[Level],[Logger],[Message],[DealID])
VALUES (#log_date,#thread,#log_level,#logger,#message,#DealID)" />
//other parameters hten DealID
<parameter>
<parameterName value="#DealID" />
<dbType value="Int32" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{DealID}" />
</layout>
</parameter>
What I found out was if I don't explicitly set using something like log4net.ThreadContext.Properties["DealID"] = DealID; it throws me an exception:
System.FormatException occurred
Message="Failed to convert parameter value from a String to a Int32."
Source="System.Data"
StackTrace:
at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
InnerException: System.FormatException
Message="Input string was not in a correct format."
Source="mscorlib"
StackTrace:
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.String.System.IConvertible.ToInt32(IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
InnerException:
I would have to set it like:
log4net.ThreadContext.Properties["DealID"] = 0;
Is there anyway that I can set a default parameter value in my log4net config for this Int32 field so that I don't need to set it explicitly to 0 if no value is supplied? And it makes me wonder why it does not happen to fields which are set as varchar (though no value is supplied to them).
Change your appender:
<parameter>
<parameterName value="#DealID" />
<dbType value="Int32" />
<layout type="log4net.Layout.RawPropertyLayout"> <!-- notice this -->
<key value="DealID" /> <!-- and notice this instead of the pattern layout -->
</layout>
</parameter>
And to give credit, I found it from this thread. (And a bunch of other searching trying to do the same thing.

Resources