I have created a WEB API. Now I want to make a log file in which I want to get all the API log information. For this, by using log4net I have created a log file.
Downloaded it from NuGet.
Add log4net in web.config file
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
<log4net>
<root>
<appender-ref ref ="LogFileAppender"/>
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="E:\MyLog\LogFile.txt"/>
<param name="AppendToFile" value ="false"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="5MB"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date [%thread] %-5level %logger - %meesage%newline"/>
</layout>
</appender>
<logger name="ApiLog">
<level value="DEBUG"/>
</logger>
</log4net>
In my Global.asax.cs file
private static readonly ILog log = LogManager.GetLogger("ApiLog");
protected void Application_Start()
{
log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
}
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
log.Debug("++++++++++++++++++++++++++++");
log.Error("Exception - \n" + ex);
log.Debug("++++++++++++++++++++++++++++");
}
Controller
public class MetersController : ApiController
{
public mdcEntities mdcEntitites = new mdcEntities();
public HttpResponseMessage GetByMsn(string msn, DateTime dt)
{
try
{
var dateTime = dt.AddHours(-1);
var result = mdcEntitites.tj_xhqd.Where(m => (m.zdjh == msn) && (m.sjsj >= dateTime))
.OrderByDescending(o => o.sjsj)
.Select(s => s.sjsj)
.FirstOrDefault();
DateTime resulted = new DateTime();
DateTime userSent = new DateTime();
resulted = Convert.ToDateTime(result);
userSent = Convert.ToDateTime(dt);
double diff = Math.Abs((resulted - userSent).TotalMinutes);
if (diff <= 10)
{
return Request.CreateResponse(HttpStatusCode.OK, new { data = new { Response = "Yes" } });
}
else
{
return Request.CreateResponse(HttpStatusCode.OK, new { data = new { Response = "No" } });
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
}
}
Now when I run this API, it did create a log file but it's empty because it will only log for errors.
How can I see my all process log including start and end timeline?
Any help would be highly appreciated
If you want log for all method you need to add log at start & end of each method like :
public HttpResponseMessage GetByMsn(string msn, DateTime dt)
{
try
{
Log.Debug(String.Format("{0} started", MethodBase.GetCurrentMethod().Name;));
...
Log.Debug(String.Format("{0} succeeded", MethodBase.GetCurrentMethod().Name;));
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
}
OR
alternative need custom action filter that triggers log after each method like given in below link:
https://www.c-sharpcorner.com/UploadFile/db2972/trace-web-api-execution-time-using-custom-action-filter/
I have added all parts of log4net, however it doesn't write to the file.
I'm working with the VS2012 LoadTest project.
Neither the System.Console.WriteLine or Debug.WriteLine() work, when running the LoadTest project.
I've added the assembly info line:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "web.config", Watch = true)] //For log4net 1.2.10.0
I've:
- added webconfig section
- initialized an configured an XML initializer
- initialized new log4net with the proper log
My app.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Settings_CacheExplosion.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>
</configuration>
My class:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17929
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WebAndLoadTestProject1
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using log4net;
using log4net.Core;
using Microsoft.VisualStudio.TestTools.WebTesting;
public class Settings_CacheExplosion : WebTest
{
private static readonly ILog activityLog = LogManager.GetLogger("Activity");
private static int _ctidsCounter { get; set; }
public static int CtidsCounter
{
get
{
if (_ctidsCounter == 2000)
{
_ctidsCounter = 1000;
}
return _ctidsCounter++;
}
set
{
_ctidsCounter = value;
}
}
public Settings_CacheExplosion()
{
this.PreAuthenticate = true;
CtidsCounter = 1000;
log4net.Config.XmlConfigurator.Configure();
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
WebTestRequest request1 = new WebTestRequest("http://clientservice.mam.qasite-services.com/settings");
request1.Method = "POST";
Debug.WriteLine(string.Format("ctid={0}", CtidsCounter));
request1.QueryStringParameters.Add("ctid", CtidsCounter.ToString(), false, false);
StringHttpBody request1Body = new StringHttpBody();
request1Body.ContentType = "";
request1Body.InsertByteOrderMark = false;
request1Body.BodyString = "";
request1.Body = request1Body;
activityLog.Debug(string.Format("ctid={0}", CtidsCounter));
//Console.WriteLine(string.Format("ctid={0}", CtidsCounter));
yield return request1;
request1 = null;
}
}
}
If you want log4net to read from the app.config, you have to add this to your AssemblyInfo.cs file:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Looking at your app.config:
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
This works to ensure that the app will refuse to start on .NET 4.0 with an error on startup.
If you are using Framework .NET4.5, log4net does not support it. See frameworks section in http://logging.apache.org/log4net/release/features.html
use <param name = "Activity" value="Settings_CacheExplosion.txt" /> instead of <file value="Settings_CacheExplosion.txt" />. in your xml configuration section.
I currently have the log4net config in the applications' app.config file, as such:
...
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\Service.log"/>
<appendToFile value="true"/>
<rollingStyle value="Date"/>
<datePattern value="yyyyMMdd"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
<logger name="Data.WebService">
<level value="ALL"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</logger>
<logger name="Data.Host.HostService">
<level value="ALL"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</logger>
</log4net>
I know I can read this in via log4net.Config.XmlConfigurator.Configure();, however, I would like to be able to update it via some sort of call as well. I'll be accepting configuration from a web service and, once I've set the new config (currently only log level, but I'm not precluding other things being configurable down the road), I need to update what is in the config file.
Having all of the configs in one file is very convenient, however, I'm open to locating the config in another file if that makes it simpler.
Since there is no official method to do so, I wound up writing a method that uses xpath to locate the element(s) to change and then update accordingly. Works well enough for what I need to do and is more elegant than a brute-force "readinthefiletoastringthenreplacethetextthensavethestringtothefile" approach.
public enum Log4NetConfigItem
{
LOGLEVEL
}
public const string LOG4NET_CONFIGFILE = "log4net.config";
public void UpdateConfiguration(Log4NetConfigItem which, object value)
{
// Load the config file.
XmlDocument doc = new XmlDocument();
doc.Load(LOG4NET_CONFIGFILE);
// Create an XPath navigator for the document.
XPathNavigator nav = doc.CreateNavigator();
try
{
XPathExpression expr;
// Compile the correct XPath expression for the element we want to configure.
switch (which)
{
default:
case Log4NetConfigItem.LOGLEVEL:
// Compile a standard XPath expression
expr = nav.Compile("/configuration/log4net/logger/level");
break;
}
// Locate the node(s) defined by the XPath expression.
XPathNodeIterator iterator = nav.Select(expr);
// Iterate on the node set
while (iterator.MoveNext())
{
XPathNavigator nav2 = iterator.Current.Clone();
// Update the element as required.
switch (which)
{
default:
case Log4NetConfigItem.LOGLEVEL:
// Update the 'value' attribute for the log level.
SetAttribute(nav2, String.Empty, "value", nav.NamespaceURI, value.ToString());
break;
}
}
// Save the modified config file.
doc.Save(LOG4NET_CONFIGFILE);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
void SetAttribute(System.Xml.XPath.XPathNavigator navigator, String prefix, String localName, String namespaceURI, String value)
{
if (navigator.CanEdit == true)
{
// Check if given localName exist
if (navigator.MoveToAttribute(localName, namespaceURI))
{
// Exist, so set current attribute with new value.
navigator.SetValue(value);
// Move navigator back to beginning of node
navigator.MoveToParent();
}
else
{
// Does not exist, create the new attribute
navigator.CreateAttribute(prefix, localName, namespaceURI, value);
}
}
}
Note: The SetAttribute code I got from here.
This is basically this open issue for log4net - unfortunately it is not resolved yet.
I have class MyLogger, where I use log4net. How can I modify my appender to save log in specific logname (I want to set it by parameter logName).
public void AddEntry(string source, string logName, string contextInfo, string message, EventLogEntryType eventType)
{
log4net.ILog Log = log4net.LogManager.GetLogger(source);
Log.Error(String.Format("Context Info: {0}{1}{2}{3}", contextInfo, Environment.NewLine, Environment.NewLine, message));
}
<log4net>
<root>
<priority value="ALL" />
<appender-ref ref="EventLogAppender" />
</root>
This is myAppender. Now it writes in common logtype Application.
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger (%property{myContext}) [%level]- %message%newline" />
</layout>
</appender>
</log4net>
I think what you are looking for is this:
<param name="LogName" value="MyLog" />
Some more information can be found here. If you do something like this you may want to have a look at this issue as well. Basically this is about registering your application so that the eventlog knows about it.
Edit (configuration by code):
Did not test it but that ought to do the trick:
foreach (AppenderSkeleton appender in this.Logger.Repository.GetAppenders())
{
var eventlogAppender = appender as EventLogAppender;
if (eventlogAppender != null)
{
eventlogAppender.LogName = "MyLog";
eventlogAppender.ActivateOptions();
break;
}
}
You could add some tests to verify that there is only one EventLogAppender, but probably you do not need to bother to do so.
this works:
<param name="LogName" type="log4net.Util.PatternString" value="%property{LogName}" />
As the title implies how can I create a new log file each day in C#? Now the program may not necessarily run all day and night but only get invoked during business hours. So I need to do two things.
How can I create a new log file each day? The log file will be have the name in a format like MMDDYYYY.txt
How can I create it just after midnight in case it is running into all hours of the night?
Update 2018: I prefer to use NLog now
Previous answer about log4net:
This example shows how to configure the RollingFileAppender to roll log files on a date period. This example will roll the log file every minute! To change the rolling period adjust the DatePattern value. For example, a date pattern of "yyyyMMdd" will roll every day.
See System.Globalization.DateTimeFormatInfo for a list of available patterns.
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\temp\rolling.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd-HHmm" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
I'd recommend something like this:
string logFile = DateTime.Now.ToString("yyyyMMdd") + ".txt";
if (!System.IO.File.Exists(logFile))
{
System.IO.File.Create(logFile);
}
//append to logFile here...
Is there a reason you want something to create it after midnight? Why not just create it if it doesn't exist when you go to log the error?
Also noticed that I changed the date format. This will allow you to sort files by name and get them in order. I always use this format when messing with dates in any way.
Others have mentioned Log4Net, so I'll go ahead and pimp the Enterprise Library Logging Block, which is also quite capable of doing what you want.
Could you please include some code that shows how easy it would be to make this roll every day? Is it easier than the log4Net example? – Daniel Dyson
Sure. Typically, one would use Enterprise Library Configuration Tool to build the configuration; this tool takes a little getting used to, but once you understand how it works, it's pretty powerful. That said, you can also edit the app.config by hand.
Here is the output of the tool I mentioned, which dumps pretty much everything into a rolling flat file that rolls every day (or if it exceeds 2MB). The formatting is the default provided by the tool.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<loggingConfiguration name="" tracingEnabled="true" defaultCategory="Category">
<listeners>
<add name="Rolling Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
formatter="Text Formatter" rollInterval="Day" rollSizeKB="2000" />
</listeners>
<formatters>
<add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
template="Timestamp: {timestamp}{newline}
Message: {message}{newline}
Category: {category}{newline}
Priority: {priority}{newline}
EventId: {eventid}{newline}
Severity: {severity}{newline}
Title:{title}{newline}
Machine: {localMachine}{newline}
App Domain: {localAppDomain}{newline}
ProcessId: {localProcessId}{newline}
Process Name: {localProcessName}{newline}
Thread Name: {threadName}{newline}
Win32 ThreadId:{win32ThreadId}{newline}
Extended Properties: {dictionary({key} - {value}{newline})}"
name="Text Formatter" />
</formatters>
<categorySources>
<add switchValue="All" name="Category">
<listeners>
<add name="Rolling Flat File Trace Listener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="All" name="All Events">
<listeners>
<add name="Rolling Flat File Trace Listener" />
</listeners>
</allEvents>
<notProcessed switchValue="All" name="Unprocessed Category">
<listeners>
<add name="Rolling Flat File Trace Listener" />
</listeners>
</notProcessed>
<errors switchValue="All" name="Logging Errors & Warnings">
<listeners>
<add name="Rolling Flat File Trace Listener" />
</listeners>
</errors>
</specialSources>
</loggingConfiguration>
</configuration>
Try out NLog (nlog-project.org). It is very flexible and easier to work with than Log4Net in my opinion.
Example NLog.config:
<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="file" xsi:type="File"
layout="${longdate} ${logger} ${message}"
fileName="${basedir}/${shortdate}/${windows-identity:domain=false}.${level}.log" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file" />
</rules>
</nlog>
For more examples (including other logging targets besides File) see NLog configuration examples on Github
You don't need to create it at a particular time- in the simplest case you can just check if there is a logfile with today's date as it's name when you start the logging service for the app and if there isn't you can create one before you start appending to it.
The only case you need to be particularly aware of with this setup is when the application runs past midnight.
use log4net. This is one of the most commonly used library for logging.
It can be easily configured as you like, please refer to samples.
Below is the appender XML that I am currently using.
Based on your requirements of
1) creating a log file for once a day and,
2) to have the extension of txt,
you should use an XML similar to what is below.
The XML below will create a log file called system-20121106.txt.
The only issue is that since file value is logs/system- your file while it is writing for current day will be system-. To get around this, you'd have to set your file value to logs/system.txt, but then you'd get system.txt.20121106.txt as the final file.
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs/system-" />
<appendToFile value="true"/>
<countDirection value="-1"/>
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd'.txt'" />
<maxSizeRollBackups value="0" />
<maximumFileSize value="10000KB" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
When you log something, check to see if a file with the current date exists, if not - create it. Simple as that :)
if(fileExists(todaysDate + ".txt")){
appendToLogFile(message);
}else{
createFile(todaysDate + ".txt");
appendToLogFile(message);
}
There is no need to create it until you need it, use:
file = new StreamWriter(path, true, new UTF8Encoding(false));
(or maybe a different encoding.) This will create the file is it does not exist, or start to append to it.
Then it is a matter of creating the filename, and just using that.
If you only need a simple TraceListener, I have a mini implementation here: https://github.com/datvm/DailyTraceListener
The output is also in CSV format so you can read it with Excel or any CSV reader.
Source code for the TraceListener:
public class DailyTraceListener : TraceListener
{
public bool UseUtcTime { get; private set; }
public string LogFolder { get; private set; }
public bool Disposed { get; private set; }
public bool HasHeader { get; private set; }
public string CurrentLogFilePath { get; private set; }
protected DateTime? CurrentLogDate { get; set; }
protected FileStream LogFileStream { get; set; }
protected StreamWriter LogFileWriter { get; set; }
private SemaphoreSlim LogLocker { get; set; } = new SemaphoreSlim(1, 1);
public DailyTraceListener(string logFolder)
{
this.LogFolder = logFolder;
}
public DailyTraceListener UseUtc()
{
this.UseUtcTime = true;
return this;
}
public DailyTraceListener UseHeader()
{
this.HasHeader = true;
return this;
}
protected virtual void WriteHeader()
{
this.LogFileWriter.WriteLine(string.Format("{0},{1},{2},{3},{4}",
"Time",
"Type",
"Source",
"ID",
"Message"));
}
protected virtual string FormatTime(DateTime time)
{
return time.ToString("o");
}
private DateTime GetCurrentTime()
{
if (this.UseUtcTime)
{
return DateTime.UtcNow;
}
else
{
return DateTime.Now;
}
}
private void InitializeLogFile()
{
this.CheckDisposed();
try
{
if (this.LogFileWriter != null)
{
this.LogFileWriter.Dispose();
}
if (this.LogFileStream != null)
{
this.LogFileWriter.Dispose();
}
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
var currentTime = this.GetCurrentTime();
var fileName = $"{currentTime.ToString("yyyy-MM-dd")}.log";
this.CurrentLogFilePath = Path.Combine(this.LogFolder, fileName);
// Ensure the folder is there
Directory.CreateDirectory(this.LogFolder);
// Create/Open log file
this.LogFileStream = new FileStream(this.CurrentLogFilePath, FileMode.Append);
this.LogFileWriter = new StreamWriter(this.LogFileStream);
// Write Header if needed
if (this.LogFileStream.Length == 0 && this.HasHeader)
{
this.WriteHeader();
}
}
private void CheckFile()
{
this.CheckDisposed();
var currentTime = this.GetCurrentTime();
if (this.CurrentLogDate == null || currentTime.Date != this.CurrentLogDate)
{
this.InitializeLogFile();
this.CurrentLogDate = currentTime.Date;
}
}
private void CheckDisposed()
{
if (this.Disposed)
{
throw new InvalidOperationException("The Trace Listener is Disposed.");
}
}
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
{
var time = this.FormatTime(this.GetCurrentTime());
this.WriteLine(string.Format("{0},{1},{2},{3},{4}",
time,
eventType,
EscapeCsv(source),
id.ToString(),
EscapeCsv(message)));
}
public override void Write(string message)
{
try
{
this.LogLocker.Wait();
this.CheckDisposed();
this.CheckFile();
var currentTime = this.GetCurrentTime();
this.LogFileWriter.Write(message);
this.LogFileWriter.Flush();
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
finally
{
this.LogLocker.Release();
}
}
public override void WriteLine(string message)
{
this.Write(message + Environment.NewLine);
}
protected string EscapeCsv(string input)
{
for (int i = 0; i < input.Length; i++)
{
if (input[i] == ',' || input[i] == '\n')
{
input = input.Replace("\"", "\"\"");
return $"\"{input}\"";
}
}
return input;
}
protected override void Dispose(bool disposing)
{
this.Disposed = true;
try
{
this.LogFileWriter?.Dispose();
this.LogFileStream?.Dispose();
this.LogLocker.Dispose();
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
base.Dispose(disposing);
}
}