Why is log4net not writing to a file? - c#

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.

Related

log4net managedcoloredconsole not working with dynamic creation

I have a program that has a different set of modules called based an input parameter. Modules like Orders, Shipments, Pricing etc. I wrote a logging class with log4net being the foundation though there is a need for some custom logging as well. What I want is to have each module have its own logging file and to that point, I was able to get log4net to dynamically create the appenders for each file.
I was also able to get a console display for the times when it may be run manually, but what I lost (and cannot figure how to get it to work is the Colored Console appender. I found the basic solution here for creating appenders and I then used this link to figure out how to create console and ManagedColoredConsole appenders, but while it still writes to the console, I do not get color.
There is something missing, but I I don't know what. I wrote a small testing program to try and figure this out and this is the logging class:
using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using System;
using System.Linq;
namespace TestLogging
{
public class Logging
{
// Since the current version of logging will require more custom fields passed into the logging table
// I'm going to set up a wrapper around the log for net processing. This should simplify the way we call it in
// the main program sections so we don't have to keep adding constants like pid and we can deal with variables
// like item, order number, shipping numbers
public static ILog log = null;
public string transType = "";
public string pid = "0";
private string logModule = "main";
private string path = "";
public Logging(string LogModule)
{
logModule = LogModule; // set up to default to main then pass in the specific log file name for log4net
SetLevel("Log4net.MainForm", "ALL");
path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
string execPath = AppDomain.CurrentDomain.BaseDirectory;
if (log.Logger.Repository.GetAppenders().Count() == 0)
{
//CreateConsoleAppender();
CreateManagedColorConsoleAppender();
}
AddAppender(LogModule, CreateFileAppender(logModule, execPath + "\\logs\\" + logModule + ".log"));
}
public void Info(string message, string sohnum = null, string itmref = null, string sdhnum = null, double processtime = 0.0)
{
setCustom(sohnum, itmref, sdhnum, processtime);
log.Info(message);
}
private void setCustom(string sohnum = null, string itmref = null, string sdhnum = null, double processtime = 0.0)
{
log4net.ThreadContext.Properties["TransType"] = transType;
log4net.ThreadContext.Properties["sohnum_0"] = sohnum;
log4net.ThreadContext.Properties["itmref_0"] = itmref;
log4net.ThreadContext.Properties["sdhnum_0"] = sdhnum;
log4net.ThreadContext.Properties["processtime"] = processtime.ToString();
log4net.ThreadContext.Properties["pid"] = pid;
}
// Set the level for a named logger
public static void SetLevel(string loggerName, string levelName)
{
log = LogManager.GetLogger(loggerName);
Logger l = (Logger)log.Logger;
l.Level = l.Hierarchy.LevelMap[levelName];
}
// Add an appender to a logger
public static void AddAppender(string loggerName, IAppender appender)
{
log = LogManager.GetLogger(loggerName);
Logger l = (Logger)log.Logger;
l.Repository.Configured = true;
l.AddAppender(appender);
}
// Create a new file appender
public static IAppender CreateFileAppender(string name, string fileName)
{
FileAppender appender = new
FileAppender();
appender.Name = name;
appender.File = fileName;
appender.AppendToFile = true;
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
return appender;
}
public static IAppender CreateConsoleAppender()
{
ConsoleAppender appender = new ConsoleAppender();
appender.Name = "console";
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Configured = true;
hierarchy.Root.AddAppender(appender);
return appender;
}
public static IAppender CreateManagedColorConsoleAppender()
{
ManagedColoredConsoleAppender appender = new ManagedColoredConsoleAppender();
ManagedColoredConsoleAppender.LevelColors mapping = new ManagedColoredConsoleAppender.LevelColors();
appender.Name = "ManagedColoredConsoleAppender";
mapping.Level = log4net.Core.Level.Debug;
mapping.ForeColor = ConsoleColor.Blue;
appender.AddMapping(mapping);
mapping.Level = log4net.Core.Level.Info;
mapping.ForeColor = ConsoleColor.Green;
appender.AddMapping(mapping);
mapping.Level = log4net.Core.Level.Error;
mapping.ForeColor = ConsoleColor.Yellow;
appender.AddMapping(mapping);
mapping.Level = log4net.Core.Level.Fatal;
mapping.ForeColor = ConsoleColor.Red;
appender.AddMapping(mapping);
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(appender);
hierarchy.Configured = true;
hierarchy.Root.Level = log4net.Core.Level.Info;
return appender;
}
}
}
It is rough, but this is just for testing and learning.
This is the main program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestLogging
{
public class Program
{
//private Logging logging = new Logging("file");
private static Logging logit = new Logging("main");
static void Main(string[] args)
{
logit.Info("This is the main program");
ordersClass orders = new ordersClass();
orders.callMe();
shipments shipit = new shipments();
shipit.shipMe();
}
}
}
and one of the classes that writes to a different log file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestLogging
{
public class ordersClass
{
private Logging logit = new Logging("orders");
public void callMe()
{
logit.Info("Just placed an order");
}
}
}
When I set a break point to look at the log object I can see managed color is there as a root appender and the others added when first created. there is not a lot of info on using log4net programmatically, but I am hoping someone got this to work.
As I was reading more I discovered how to turn on internal logging for log4net. Put that in the app.config file and yes, it helps for it showed me how to fix my issue though why it does not work dynamically still alludes me.
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
What I found was a few things:
Log4net does not need a config file to work if you are setting things up programmatically. Found that out because I had not set the 'copy to output directory' to other then 'do not copy' so no config file was being put in the the exe folder. This showed me you don't need a config file to do logging, but it still did not answer why no color.
If you decide to use a config file, but don't put in a appender that is referenced in the root, log4net logs the error, but keeps working. I had this
<appender-ref ref="ManagedColoredConsoleAppender" />
but no appender in the file. I added the ManagedColorConsole Appender and now I am getting both colored console messages AND logging into multiple files. This is a solution, but does not explain why I could add the color appender dynamically, but not have it work. If there is an answer please post. In the mean time this is a solved question.
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="ManagedColoredConsoleAppender" />
</root>
<appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="INFO" />
<foreColor value="Green, HighIntensity" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="Green" />
</mapping>
<mapping>
<level value="ERROR" />
<foreColor value="Yellow, HighIntensity" />
</mapping>
<mapping>
<level value="FATAL" />
<foreColor value="Red, HighIntensity" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
</log4net>

Unable to load shared library 'Kernel32.dll' or one of its dependencies. In order to help diagnose loading problems

Hello friends I have the following problem when trying to run my application in Linux Ubuntu x64, my application is written in Net Core C # with listening socket.
my code is net core 3.1:
using log4net;
using log4net.Config;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Teltonika.Codec;
namespace UdpListener
{
class Program
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
XmlConfigurator.Configure();
IPAddress ip;
if (!IPAddress.TryParse(ConfigurationManager.AppSettings["ipAddress"], out ip))
{
Log.Error("Ip is not valid.");
throw new ArgumentException("Ip is not valid.");
}
int port;
if (!int.TryParse(ConfigurationManager.AppSettings["port"], out port))
{
Log.Error("Port is not valid.");
throw new ArgumentException("Port is not valid.");
}
Task.Run(async () =>
{
try
{
using (var udpClient = new UdpClient(new IPEndPoint(ip, port)))
{
Log.Info("Listening...");
while (true)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
byte[] data = receivedResults.Buffer;
Log.Info(string.Format("Received connection from: {0}", receivedResults.RemoteEndPoint));
Log.Info(string.Format("{0} - received [{1}]", DateTime.Now, String.Join("", data.Select(x => x.ToString("X2")).ToArray())));
var reader = new ReverseBinaryReader(new MemoryStream(data));
// Decode data
var avlData = new DataDecoder(reader).DecodeUdpData();
// Create response
var bytes = new List<byte>();
const short packetLength = 2 /* Id /+ 1 / Type / + 1 / Avl packet id /+ 1 / num of accepted elems */;
bytes.AddRange(BitConverter.GetBytes(BytesSwapper.Swap(packetLength)));
bytes.AddRange(BitConverter.GetBytes(BytesSwapper.Swap(avlData.PacketId)));
bytes.Add(avlData.PacketType);
bytes.Add(avlData.AvlPacketId);
bytes.Add((byte)avlData.AvlData.DataCount);
var response = bytes.ToArray();
Log.Info(string.Format("{0} - response [{1}]", DateTime.Now, String.Join("", bytes.Select(x => x.ToString("X2")).ToArray())));
await udpClient.SendAsync(response, response.Length, receivedResults.RemoteEndPoint);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
});
Console.ReadLine();
}
}
}
my configurations setting app.config :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<appSettings>
<add key="ipAddress" value="198.199.67.142"/>
<add key="port" value="777"/>
<!--<add key="log4net.Internal.Debug" value="true"/>-->
</appSettings>
<log4net>
<appender name="Console" type="log4net.Appender.ColoredConsoleAppender" Target="Console.Error">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger - %message%newline"/>
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="500KB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d %-5p %c %m%n"/>
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileAppender"/>
</root>
</log4net>
</configuration>
this is the error code i get, when I try to run it within linux ubuntu it returns this error:
log4net:ERROR Could not create Appender [Console] of type [log4net.Appender.ColoredConsoleAppender]. Reported error follows.
System.DllNotFoundException: Unable to load shared library 'Kernel32.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libKernel32.dll: cannot open shared object file: No such file or directory
at log4net.Appender.ColoredConsoleAppender.GetConsoleOutputCP()
at log4net.Appender.ColoredConsoleAppender.ActivateOptions()
at log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseAppender(XmlElement appenderElement)
log4net:ERROR Appender named [Console] not found
Please Help.

How to configure log4net with VSTO project in visual studio

I was trying to build a simple outlook add in.
I created a VSTO project in Visual Studio 2017.
When the project is created by the Visual Studio, there is no app.config or web.config in the solution. I want to use log4net for this project. How should I configure it? I tried to add web.config or app.config for the project. But I was not able to get values from the configure file. I think the project cannot recognize them. I cannot use ConfigurationManager.AppSettings["key"] to get the value from the configure file.
Does anyone know how to use log4net in VSTO project?
Thank you.
Install Log4Net through the NuGet Package Manager. Then create a setting in the project properties, like asdf (you can delete the setting after you update the app.config file with the Log4Net sections), it will then create the app.config for you.
Here's the configuration in app.config for Log4Net I use on most of my projects. I created a new project with a setting asdf and added my standard Log4Net setup.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="ExcelAddIn1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<userSettings>
<ExcelAddIn1.Properties.Settings>
<setting name="asdf" serializeAs="String">
<value>asdf</value>
</setting>
</ExcelAddIn1.Properties.Settings>
</userSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline"/>
</layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="C:\Temp\MyOfficeAddIn.log"/>
<appendToFile value="true"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date|%-5level|%message%newline"/>
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="FileAppender"/>
</root>
</log4net>
</configuration>
I usually create a class called ErrorHandler and add the following code.
using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using log4net;
using log4net.Config;
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Then I use the following methods to write to the log file
private static readonly ILog log = LogManager.GetLogger(typeof(ErrorHandler));
/// <summary>
/// Applies a new path for the log file by FileAppender name
/// </summary>
public static void SetLogPath()
{
XmlConfigurator.Configure();
log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
string logFileName = System.IO.Path.Combine(Properties.Settings.Default.App_PathLocalData, AssemblyInfo.Product + ".log");
foreach (var a in h.Root.Appenders)
{
if (a is log4net.Appender.FileAppender)
{
if (a.Name.Equals("FileAppender"))
{
log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a;
fa.File = logFileName;
fa.ActivateOptions();
}
}
}
}
/// <summary>
/// Create a log record to track which methods are being used.
/// </summary>
public static void CreateLogRecord()
{
try
{
// gather context
var sf = new System.Diagnostics.StackFrame(1);
var caller = sf.GetMethod();
var currentProcedure = caller.Name.Trim();
// handle log record
var logMessage = string.Concat(new Dictionary<string, string>
{
["PROCEDURE"] = currentProcedure,
["USER NAME"] = Environment.UserName,
["MACHINE NAME"] = Environment.MachineName
}.Select(x => $"[{x.Key}]=|{x.Value}|"));
log.Info(logMessage);
}
catch (Exception ex)
{
ErrorHandler.DisplayMessage(ex);
}
}
/// <summary>
/// Used to produce an error message and create a log record
/// <example>
/// <code lang="C#">
/// ErrorHandler.DisplayMessage(ex);
/// </code>
/// </example>
/// </summary>
/// <param name="ex">Represents errors that occur during application execution.</param>
/// <param name="isSilent">Used to show a message to the user and log an error record or just log a record.</param>
/// <remarks></remarks>
public static void DisplayMessage(Exception ex, Boolean isSilent = false)
{
// gather context
var sf = new System.Diagnostics.StackFrame(1);
var caller = sf.GetMethod();
var errorDescription = ex.ToString().Replace("\r\n", " "); // the carriage returns were messing up my log file
var currentProcedure = caller.Name.Trim();
var currentFileName = AssemblyInfo.GetCurrentFileName();
// handle log record
var logMessage = string.Concat(new Dictionary<string, string>
{
["PROCEDURE"] = currentProcedure,
["USER NAME"] = Environment.UserName,
["MACHINE NAME"] = Environment.MachineName,
["FILE NAME"] = currentFileName,
["DESCRIPTION"] = errorDescription,
}.Select(x => $"[{x.Key}]=|{x.Value}|"));
log.Error(logMessage);
// format message
var userMessage = new StringBuilder()
.AppendLine("Contact your system administrator. A record has been created in the log file.")
.AppendLine("Procedure: " + currentProcedure)
.AppendLine("Description: " + errorDescription)
.ToString();
// handle message
if (isSilent == false)
{
MessageBox.Show(userMessage, "Unexpected Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
I have a project in GitHub you can use as an example.

Set log name in appender of log4net

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}" />

Creating a new log file each day

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);
}
}

Categories

Resources