extend log4net SmtpAppender for dynamic To email address - c#

Ok. I have created custom SmtpAppender to use dynamic To email address.
Using sample project given with Log4net - I have managed to use dynamic email address as below
log4net.ThreadContext.Properties["ToProperty"] = "swapneel#stackoverlfow.com";
and in my custom SMTPAppender
string mailMessageTo;
if (ToProperty == null)
{
mailMessageTo = "DoNotReply#StaockOverlfow.com" }
else
{
var subjectWriter = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
ToProperty.Format(subjectWriter, loggingEvent);
mailMessageTo = subjectWriter.ToString();
}
this code is working in sample application but when I am trying to use it in our "Project" not working for some reason.
I have 2 appenders in Log4net.config. EventLog is working as expected but CustomSmtpAppender is not sending any emails. Any direction to resolve this issue.
1] <appender name ="EmailLogAppender1" type ="MY.Company.ProjectName.Appenders.CustomSmtpAppender,
TRS">
2] <appender name ="EventLogAppender" type="log4net.Appender.EventLogAppender" >

I enabled log4net internal debugging and could see what was causing problem.
Add this to your Web.Config:
<appSettings>
<add key="log4net.Internal.Debug" value="true" />
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="c:\\log4net.txt" />
</listeners>
</trace>
</system.diagnostics>

Related

Using EventLogTraceListener inside a library DLL

I've written a library that gets called by several applications all residing in the same folder. Currently it's using log4net with the log4net.config file for event logging which works well. But log4net is now a dormant project with no foreseeable updates, and it appears that EventLogTraceListener can accomplish much the same thing without relying on a 3rd party library. However, I'm not sure there's a way to use an app.config file (out of the box) with a DLL. For example, the app.config file below works in a console app (MyApp.exe.config) but won't work when only using my DLL (MyLibrary.dll.config):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<system.diagnostics>
<trace autoflush="true" indentsize="0">
<listeners>
<add name="MyListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="MyListener.log"/>
<add name="MyEventListener" type="System.Diagnostics.EventLogTraceListener" initializeData="MyLog"/>
</listeners>
</trace>
<switches>
<add name="MySwitch" value="Verbose"/>
</switches>
</system.diagnostics>
</configuration>
From doing some research it appears that config files for DLLs aren't really viable since the calling app's config file is normally used. But I don't want to have to edit the config file of multiple applications to change logging level, etc. I realize I could roll my own but it's nice that .NET has all this functionality built-in. Just need to know if there's a way to make it work using a DLL.config file?
var log = Trace.Listeners.OfType<EventLogTraceListener>().First(); // Works for an app but not a DLL (no listener)
log.TraceEvent(new TraceEventCache(), "Delme1", TraceEventType.Verbose, 123, "Testing");
UPDATE #1
Based on the answers here it doesn't look like this is supported by design. There also doesn't appear to be any user available objects for manipulating the systems.diagnostic entries. I think I'm going to just create my own XML file for storing the info I need.
UPDATE #2
Per Microsoft's recommendation, I switched to using the TraceSource class and updated my config file to match. I found a way to dynamically load the file from a DLL but that doesn't appear to update the TraceSource class settings, even after issuing a Trace.Refresh(). Everything works when I create a config file with the same settings at the application level, but that's not what I want. Is there any way to load a config file as shown below and also have its settings update the TraceSource class with Listeners, etc.? I find it curious that SystemDiagnosticsSection is marked internal and not accessible to user apps. Seems Microsoft has made this nearly(?) impossible (but I'm so close!)
Config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="MyExceptionLibrary" switchName="MySwitch" switchType="System.Diagnostics.SourceSwitch">
<listeners>
<remove name="Default"/>
<add name="MyListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Logger.log">
<filter type="System.Diagnostics.EventTypeFilter" initializeData="Off"/>
</add>
<add name="MyEventListener" type="System.Diagnostics.EventLogTraceListener" initializeData="Blah">
<filter type="System.Diagnostics.EventTypeFilter" initializeData="Verbose"/>
</add>
</listeners>
</source>
</sources>
<switches>
<add name="MySwitch" value="Verbose"/>
</switches>
</system.diagnostics>
</configuration>
Code:
public static class Logger
{
private static readonly TraceSource s_traceSource = new TraceSource("MyExceptionLibrary");
static Logger()
{
var config = ConfigurationManager.OpenExeConfiguration("MyExceptionLibrary.dll"); // Confirmed config loaded
ConfigurationManager.RefreshSection("system.diagnostics"); // Doesn't seem to make any difference
Debug.WriteLine($"Config file: {config.FilePath}"); // Points to new config file
var section = config.GetSection("system.diagnostics"); // Contains data from file
Debug.Write(section.SectionInformation.Type); // SystemDiagnosticSection
Trace.Refresh(); // Doesn't seem to make any difference
Debug.WriteLine(s_traceSource.Listeners[0].Name); // Still shows Default
s_traceSource.TraceEvent(TraceEventType.Verbose, 123, "Testing"); // No event log entry is created
}
}

How to use trace sources in application code?

I have successfully configured logging in the App.config file of an application. The relevant parts are as follows.
<system.diagnostics>
<sources>
<source name="System.Net.Http">
<listeners>
<add name="PushTraceListener" />
</listeners>
</source>
</sources>
<switches>
<add name="System.Net.Http" value="Verbose"/>
</switches>
<sharedListeners>
<add name="PushTraceListener"
type="PushCore.Logging.LoggingTraceListener, PushCore" />
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000"/>
</diagnostics>
</system.serviceModel>
While this works fine, I seem unable to do the same in the application code, which I tried as follows.
var LoggingTraceListener = new LoggingTraceListener
{ Name = "PushTraceListener", Filter = new LoggingTraceFilter() };
Trace.AutoFlush = true;
var TraceSourceNames = new string[] { "System.Net.Http" };
foreach (var TraceSourceName in TraceSourceNames)
{
var TraceSource = new TraceSource(TraceSourceName, SourceLevels.Verbose);
TraceSource.Switch = new SourceSwitch(TraceSourceName, "Verbose");
TraceSource.Listeners.Add(LoggingTraceListener);
}
Trace.Listeners.Add(LoggingTraceListener);
The TraceListener itself seems to behave as expected, as it recieves messages written via Trace, but apparently not from the instantiated TraceSource instance. I somehow believe that instantiation of the TraceSource is not desired here, but instead an existing trace source would have to be used. However, I don't know how to do that.
Is it possible to achieve loggig as desired in the first place? If so, how?
A justified question would be why I would like to do access in code instead of using App.config if the configuration works fine. The reason is that App.config can only be used for an actual application but not for a Windows service.
Any suggestions?

Using TraceSource from a class library and using it in other components of the same executable

I have created a library for event logging utilities using system.Diagnostics like the one below:
public class Logger
{
static TraceSource ts = new TraceSource("TestApp");
public void Log(string message)
{
ts.TraceEvent(TraceEventType.Verbose, 0, message);
}
}
I want to use this Log function in my app and other components (dll) of the same application. I tried declaring listeners in app.config of my application, but it didnt work :(. My app.config looks like below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="TestApp"
switchName="mySwitch"
switchType="System.Diagnostics.SourceSwitch" >
<listeners>
<clear/>
<add name="EventLogListener"
type="System.Diagnostics.EventLogTraceListener"
initializeData="Title for events" />
</listeners>
</source>
</sources>
<switches>
<add name="mySwitch" value="Verbose" />
</switches>
</system.diagnostics>
</configuration>
If i move the class Logger in the application itself (the executable), with the given manifest file, i could see the logs in the application channed in the eventviewer. But i dont want to use it this way.
Can someone please help me find out what is the underlying problem here?
I realized that "Trace" was not enabled for the class library in the csproj. After enabling that i am at least seeing those events in textwriterListener/

Can I turn off tracing for a single assembly that my code references?

I have a certain framework of code, and I have a TraceListener defined for two reasons:
Back-compatibility with a lot of the old logging that was done via Trace.Write until we update it, and
It's nice to be able to instrument the other assemblies our code references if we need to.
However, I have one assembly (not ours) that logs a lot of pointless data that doesn't help us debug anything. How can I turn off tracing for this one assembly (or, alternately, the facade project we built around it), while leaving it on for the rest of the application?
I've tried various flavors of configuration in our facade project, usually looking like the following, to no avail. I've tried adding <remove> elements that match the <add> elements which setup the logging in the first place, tried <clear>ing them, setting <trace enabled="false"> and at least three other attempts. Thanks for any help you can provide!
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<clear/>
</listeners>
</trace>
<switches>
</switches>
</system.diagnostics>
You can write your own trace filter, for use with your TraceListener. Inside this filter you can look for your assembly in stackTrace and turn off event tracing.
In my case I wrote filter (see: DotNetOpenAuthFilter) based on EventTypeFilter, which filters events only from the DotNetOpenAuth library.
Then connect the filter to the listener in the web.config:
<configuration>
<system.diagnostics>
<trace>
<listeners>
<add name="console" type="System.Diagnostics.ConsoleTraceListener" >
<filter type="Common.Log.DotNetOpenAuthFilter, Common" initializeData="Warning" />
</add>
</listeners>
</trace>
</system.diagnostics>
</configuration>
Use TraceSource.
Initialize it in your trace source.
TraceSource logger = new TraceSource("Class1");
Call it from critical points in code:
logger.TraceInformation("Hello from Class1");
Be sure to edit your application configuration:
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="Class1" switchName="Class1Switch" switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="console"></add>
<add name="csv" />
<!-- or you can add your own listener here -->
</listeners>
</source>
</sources>
<switches>
<add name="Class1Switch" value="Information" />
</switches>
<sharedListeners>
<add name="console" type="System.Diagnostics.ConsoleTraceListener" />
<add name="csv" type="System.Diagnostics.DelimitedListTraceListener"
delimiter="|" initializeData="d:\data\tracing\trace.log"
traceOutputOptions="Timestamp, ThreadId, LogicalOperationStack, DateTime, ProcessId">
</add>
</sharedListeners>
</system.diagnostics>
If say, you want to only log errors, change the switch:
<add name="Class1Switch" value="Error" />
To switch it completely off:
<add name="Class1Switch" value="Off" />

WCF Tracing From Code

I have all of my connections set up from my code, as opposed to using my config file. How does one go about setting up WCF Tracing on a connection built from code. I tried adding the tracing to the config file, as explained here, but it produces no logs whatsoever.
I need to know either how to make it work from the config file for connections set up in code, or how to configure it manually in code if anyone has any info. Thanks!
EDIT: To add a little more information:
The application is a C# Console application, and my binding is declared as:
private Binding getBinding()
{
NetTcpBinding tcp = new NetTcpBinding();
tcp.ReaderQuotas.MaxArrayLength = 65535;
tcp.TransferMode = TransferMode.Streamed;
tcp.ReaderQuotas.MaxArrayLength = int.MaxValue;
tcp.ReaderQuotas.MaxDepth = int.MaxValue;
tcp.ReaderQuotas.MaxStringContentLength = int.MaxValue;
tcp.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
tcp.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
tcp.MaxReceivedMessageSize = int.MaxValue;
return tcp;
}
And I then add services to my app using a generic function:
private List<ServiceHost> m_Hosts = new List<ServiceHost>();
private static List<string> m_Services = new List<string>();
public void AddHost<T1, T2>(string uri)
where T1 : class
where T2 : class
{
m_Services.Add("net.tcp://<ipaddress>:<port>/" + uri);
m_Hosts.Add(new ServiceHost(typeof(T1)));
m_Hosts[m_Hosts.Count - 1].AddServiceEndpoint(typeof(T2), getBinding(), m_Services[m_Services.Count - 1]);
}
There's obviously a little more code to make this all work, but this should give any relevant parts.
The following is an .config example to enable tracing, if you want to give it another attempt. Make sure the .config file is located in the same folder of your WCF service host.
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning" propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource" switchValue="Warning, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="TraceLog.svclog" />
</sharedListeners>
</system.diagnostics>
</configuration>
Microsoft provides a Service Trace Viewer Tool to read .svclog files.
Make sure the path where you will be saving the .svclog has the necessary write permissions.
Just for the records here is how to change the log file name by code
http://geekswithblogs.net/FlippinIT/archive/2009/11/12/wcf-tracing-in-code.aspx

Categories