log4net cant insert data to custom column - log4net

Writing db for base lognet columns fine, but I added another column called "clientIp" and set data to Ilog object bofore log but it writes same data with Message column to ClintIp column.. here my config and file and db screenshot:
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
...
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception],[ClientIp]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception, #clientip)" />
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
...
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
<parameter>
<parameterName value="#clientip" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" />
</parameter>
</appender>
and my logger class:
public static class Logger
{
private static ILog log {get; set;}
static Logger()
{
log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
public static void Error(object msg, string userip)
{
log4net.LogicalThreadContext.Properties["ClientIp"] = userip;
if (log.IsErrorEnabled)
{
log.Error(msg);
}
}
whats is problem here ?
EDITED:
Its obvious, it writes db with for message and clientip with given parameter: for exmp: log.Error('Your Ip is::1'); how can I tell log4net use log4net.LogicalThreadContext.Properties["ClientIp"] for ClientIp column and log.error(message) for Message column

Your code is not correct, it should be:
public static void Error(object msg, string userip)
{
log4net.LogicalThreadContext.Properties["ClientIp"] = userip;
if (log.IsErrorEnabled)
{
log.Error(msg); //<----Here is your error
}
}
And add in the ip column:
<parameter>
<parameterName value="#clientip" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" >
<conversionPattern value="%property{ClientIp}" />
</layout>
</parameter>

In case this helps anyone else, I had the same problem: the data in my added column was "somewhat" repeated from the Message column.
For example, I was simply logging "accessed home page" as the message. My added column had "accessed home pageac" showing up in it.
My first mistake was having a value attribute after the layout type:
Removing the value attribute from above prevented the data from being duplicated in the added column, but now the column was null.
My second mistake was that for some unknown reason, log4net does NOT like 'machinename'. I don't know if the problem is the column name, or the parameter name, but I changed all instances of 'machinename' to 'server' (including renaming the column in the DB of course), and it all started working.
EDIT
Ok so I think I just realized that the problem was the Properties value is case sensitive, so I was using .Properites["MachineName"] but should have been using .Properties["machinename"].

Related

log4net not logging precise time to DB

I have DB logging setup through log4net. I'm getting same timestamps & no exception object.
Appender:
<appender name="AsyncDBAppender" type="DA.Systems.Focus.Shared.LogCore.AsynchronousAdoNetAppender, Focus-Shared-LogCore">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=dbServer;initial catalog=dbName;persist security info=True;user id=username;password=password;MultipleActiveResultSets=True;Connect Timeout=360;App=log4net" />
<commandText value="INSERT INTO [dbo].[MainLog] ([ProjectId], [ApplicationId], [MachineName],[OperationId], [UserId], [Date], [Thread] ,[Level], [Logger], [Message], [Exception])
VALUES (1, 2, #machineName, #operationId, #userId, #logDate, #thread, #logLevel, #logger, #message, #exception)" />
<parameter>
<parameterName value="#machineName" />
<dbType value="String" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{log4net:HostName}" />
</layout>
</parameter>
<parameter>
<parameterName value="#operationId" />
<dbType value="String" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{OperationId}" />
</layout>
</parameter>
<parameter>
<parameterName value="#userId" />
<dbType value="String" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{UserId}" />
</layout>
</parameter>
<parameter>
<parameterName value="#logDate" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#thread" />
<dbType value="String" />
<size value="32" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%t" />
</layout>
</parameter>
<parameter>
<parameterName value="#logLevel" />
<dbType value="String" />
<size value="512" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%p" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="512" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%c" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%m" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
Produces this log:
Issues:
Sorting by date destroys the actual sequence. The pattern is a log4net.Layout.RawTimeStampLayout & the database column is Datetime2
When there was an exception, the exception itself didn't get logged
Exploding code:
try
{
InfoScope($"{LayerName} -> {callerInfo.MethodName} -> Passes bill created. Notifying Security-System...", userId, operationId);
var notificationResult = await _securitySystem.FocusBillPaymentNotification(billInfoBdo.BillDetails, userId, operationId);
if (notificationResult.Result)
{
InfoScope($"{LayerName} -> {callerInfo.MethodName} -> Notifying Security-System succeeded: Security-System Receipt #{notificationResult.SecuritySystemReceiptNumber}, Message: {notificationResult.Message}", userId, operationId);
}
else
{
WarnScope($"{LayerName} -> {callerInfo.MethodName} -> Notifying Security-System failed: {notificationResult.Message}", userId, operationId);
}
}
catch (Exception exp)
{
ErrorScope($"{LayerName} -> {callerInfo.MethodName} -> Exception at Security-System Payment notification [{exp.Message}]", exp, userId, operationId);
}
How do I make the time stamp more precise?
Why would the exception pobject not get .ToString()/logged?
Here is the Logging Core I use:
#region Error
[DebuggerStepThrough]
protected void ErrorScope(string message, string userId, Guid operationId)
{
SetUserId(userId);
SetOperationId(operationId);
Logger.ErrorFormat(message);
}
[DebuggerStepThrough]
protected void ErrorScope(string message, Exception exception, Guid operationId)
{
SetOperationId(operationId);
Logger.ErrorFormat(message, exception.GetInnerExceptions());
}
[DebuggerStepThrough]
protected void ErrorScope(string message, Exception exception, string userId, Guid operationId)
{
SetUserId(userId);
ErrorScope(message, exception, operationId);
}
#endregion
Well, this is not a direct solution to the issue but I did manage to get a proper timestamp in a different manner: I added another column to DB with type as DateTime2 and default as SysDateTime():
RecordStamp DATETIME2 NOT NULL CONSTRAINT DF_MainLog_RecordStamp DEFAULT (SYSDATETIME())
Now, this column is responsible for ensuring each log entry with a valid timestamp.

DateTime format in log4net AdoNetAppender

I'm using log4net and trying to pass a custom DateTime property to a database using the AdoNetAppender. I can pass in the DateTime value just fine, but the database value excludes the milliseconds. The final value is rounded to the nearest second.
I know there's the date{} formatting, but I cannot get that to work with a custom property. So, is it possible to format a custom DateTime property to include the milliseconds?
Here's my config:
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="0" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="{MyConnectionString}" />
<commandText value="INSERT INTO MyTestLog ([Date],[Thread],[Level],[Logger],[Message],[Exception],[StartDate]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception, #start_date)" />
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
<parameter>
<parameterName value="#start_date"/>
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{StartDate}" />
</layout>
</parameter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
</root>
</log4net>
My logging code is:
ThreadContext.Properties["StartDate"] = DateTime.Now.AddMinutes(-10);
log.Info("Info message w/ StartTime property");
The resulting value is correct (10 minutes ago), but the value is rounded to the nearest second.
I can get it to work if I first reformat the DateTime to a String, like this:
ThreadContext.Properties["StartDate"] = DateTime.Now.AddMinutes(-10).ToString("yyyy-MM-ddTHH:mm:ss.fffzzz");
However, this seems less than optimal. Any ideas??
Option 1
Use log4net.Layout.RawPropertyLayout instead; e.g:
<parameter>
<parameterName value="#start_date"/>
<dbType value="DateTime" />
<layout type="log4net.Layout.RawPropertyLayout">
<key value="StartDate" />
</layout>
</parameter>
Option 2
Create this (it could be a struct if you prefer and might reduce heap allocations depending on how you use it):
public class Log4NetDateTime
{
private DateTime _value;
public Log4NetDateTime(DateTime value)
{
_value = value;
}
public override string ToString()
{
return _value.ToString("yyyy-MM-dd HH:mm:ss.fff");
}
}
Then add Log4NetDateTime values instead of DateTime values.
log4net.Layout.PatternLayout (via log4net.Util.PatternConverter) just calls ToString() on the object, and by default this does not include milliseconds.

SQL appender for log4net not working in MVC5 application

I can't get log4net to actually log anything to my database. First I added log4net to my project (MVC).
Then I added this in AssemblyInfo.cs
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
In Global.asax.cs Application_Start I end the method with
log4net.GlobalContext.Properties["ApplicationName"] = "MvcApp";
log.Debug("Application started");
I added the following model:
public class Log
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[Display(Name="Date")]
public DateTime Description { get; set; }
[Required, StringLength(255)]
[Display(Name="Thread")]
public string Thread { get; set;}
[Required, StringLength(50)]
[Display(Name = "Level")]
public string Level { get; set; }
[Required, StringLength(255)]
[Display(Name = "Logger")]
public string Logger { get; set; }
[Required, StringLength(4000)]
[Display(Name = "Message")]
public string Message { get; set; }
[Required, StringLength(2000)]
[Display(Name = "Exception")]
public string Exception { get; set; }
}
I added this to ApplicationDbContext:
public System.Data.Entity.DbSet<Models.Log> Logs { get; set; }
In web.config I added this in the configSections element:
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
And then I created this as a child of the configuration element in web.config:
<log4net debug="true">
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="100" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="Server=windflower.arvixe.com;Initial Catalog=coralys;User Id=coralysdb;Password=CoughUp_23;Application Name=CoralysInternet;" />
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception)" />
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="#thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="#logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="#message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="#exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="AdoNetAppender" />
</root>
But even with the log.Debug entries nothing is appended. I tried setting the buffer to 5 as a test but no result. I then added a method to flush the buffers as well, no result. And the level is set to maximum (DEBUG).
What else am I missing here?
It finally works. What helped was to enable Internal Debug on log4net and have it log to internal debug to a text file as described in
Log4net with Entity Framework 5 and MVC4
Having done that it turned out that the SQL statement was wrong, my log table had a different name and also by mistake I had named the Date column as Description. All those errors appeared in the internal debug.
Having fixed that, it worked.

DateTimeOffset in Log4Net

What is log4net.Layout.PatternLayout value to output DateTimeOffset data type to database?
This is what I have currently in configuration file for log4net:
<log4net>
....
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" />
</parameter>
...
</log4net>
And I want to have something like:
<log4net>
....
<parameter>
<parameterName value="#log_date" />
<dbType value="DateTimeOffset" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff **OFFSET**}" />
</parameter>
...
</log4net>
Basically we reuse the same DB to log events from clients located in different time zones - so we want to know an exact local time of the event.
Thanks,
Alex
You should be able to use any valid DateTime format string. Try this:
%date{yyyy-MM-ddTHH:mm:ss.fffzzz}
Would defining your DB column as DateTime and using %utcdate instead of %date help? That should make all of the timestamps compatible.

Log log4net numeric level value

I would like to log the numeric value corresponding to the log level when using log4net. That is, right now I am logging to database with the following command text:
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (#log_date, #thread, #log_level, #logger, #message, #exception)" />
<parameter>
<parameterName value="#log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
I would like to change the string value of the logging level to the numeric. Is this possible?
I did not test this but the following should work.
You can create your own converter like this:
sealed class NumericLevelPatternConverter : PatternLayoutConverter
{
override protected void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
// maybe you need to call ToString() on the value property
writer.Write( loggingEvent.Level.Value );
}
}
and in the configuration file:
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="levelId" />
<type value="YourNamespace.NumericLevelPatternConverter" />
</converter>
<conversionPattern value="%levelId" />
</layout>

Resources