Dynamic log file Names with log4net
If you needed to generate dynamic logfile names with log4net then you can use the following config
1: <appender name="RollingFileAppenderV1" type="log4net.Appender.RollingFileAppender">
2: <file type="log4net.Util.PatternString" value="F:\HornetFeed\%property{LogName}" />
3: <appendToFile value="true" />
4: <rollingStyle value="Size" />
5: <maxSizeRollBackups value="-1" />
6: <maximumFileSize value="5000KB" />
7: <staticLogFileName value="true" />
8: <countDirection value="1"/>
9: <layout type="log4net.Layout.PatternLayout">
10: <conversionPattern value="%m%n" />
11: </layout>
12: <filter type="log4net.Filter.PropertyFilter">
13: <Key value="Version" />
14: <StringToMatch value="1" />
15: </filter>
16: <filter type="log4net.Filter.DenyAllFilter" />
17: </appender>
Note the %property{LogName} this is a log4net Property which we can set at runtime using C# code.
1: log4net.GlobalContext.Properties["LogName"] = "file1.log";
Remember to set the GlobalContext Properties before instantiating the log4net logger. i.e. before this call:
1: log4net.ILog log = LogManager.GetLogger(typeof(Program));
Also note the “PropertyFilter”
1: <filter type="log4net.Filter.PropertyFilter">
2: <Key value="Version" />
3: <StringToMatch value="1" />
4: </filter>
This Property is also set dynamically at runtime using C# code. We can use ThreadContext to determine which logfile the log entry will be written to. Thus if you wanted that the RollingFileAppenderV1 was used for writing insure that the Thread calling the log.Warn method precedes the call with this following line
1: log4net.ThreadContext.Properties["Version"] = "1";
If you wanted to use RollingFileAppenderV1 always for logging all messages other than Exception messages then use the following
1: try
2: {
3: log4net.GlobalContext.Properties["Version"] = "1";
4: //Business logic with many log.Warn calls
5: }
6: catch (Exception ex)
7: {
8: LogError(ex);
9: }
10:
11: ///Helper method to log errors:
12: internal static void LogError(Exception ex)
13: {
14: string state = "1";
15: if(log4net.ThreadContext.Properties["Version"] != null)
16: state = log4net.ThreadContext.Properties["Version"].ToString();
17: log4net.ThreadContext.Properties["Version"] = "0";
18: logger.HandleException(ex, "Error");
19: log4net.ThreadContext.Properties["Version"] = state;
20: }
Note I am using GlobalContext and hence all threads will use this setting to write to log files. No need to set the TrheadContext.Properties on individual threads.
But I prefer to use ThreadContext so that we can control the setting on each thread level.
Also make sure the log4net XML config is set as follows:
1: <log4net>
2: // the following logs only those logs when the Property Version is set to 1 i.e.
3: // if Version =1 then log.Warn calls are logged to this dynamically named file
4: <appender name="RollingFileAppenderV1" type="log4net.Appender.RollingFileAppender">
5: <file type="log4net.Util.PatternString" value="F:\HornetFeed\%property{LogName}" />
6: <appendToFile value="true" />
7: <rollingStyle value="Size" />
8: <maxSizeRollBackups value="-1" />
9: <maximumFileSize value="5000KB" />
10: <staticLogFileName value="true" />
11: <countDirection value="1"/>
12: <layout type="log4net.Layout.PatternLayout">
13: <conversionPattern value="%m%n" />
14: </layout>
15: <filter type="log4net.Filter.PropertyFilter">
16: <Key value="Version" />
17: <StringToMatch value="1" />
18: </filter>
19: <filter type="log4net.Filter.DenyAllFilter" />
20: </appender>
21:
22: //The following matches and logs all events except Version=1 and Version=2 and strings containing CACHE_CALL_LOG
23:
24: <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
25: <file type="log4net.Util.PatternString" value="F:\logfiles\trace.log" />
26: <appendToFile value="true" />
27: <rollingStyle value="Size" />
28: <maxSizeRollBackups value="10" />
29: <maximumFileSize value="3000KB" />
30: <staticLogFileName value="true" />
31: <countDirection value="1"/>
32: <layout type="log4net.Layout.PatternLayout">
33: <conversionPattern value="%d [%t] %-5p %c [%x] - %m%n" />
34: </layout>
35: <filter type="log4net.Filter.PropertyFilter">
36: <Key value="Version" />
37: <StringToMatch value="1" />
38: <acceptOnMatch value="false" />
39: </filter>
40: <filter type="log4net.Filter.PropertyFilter">
41: <Key value="Version" />
42: <StringToMatch value="2" />
43: <acceptOnMatch value="false" />
44: </filter>
45: <filter type="log4net.Filter.StringMatchFilter">
46: <stringToMatch value="CACHE_CALL_LOG" />
47: <acceptOnMatch value="false" />
48: </filter>
49: </appender>Posted in: programming asp.net | Tags: log4net dynamic log file file name path log path
log4net Dynamic Properties in XML Configuration.
I just learned about a new feature today of log4net that would have saved me a few hours of time had I known or been able to find this earlier. I learned that you can have dynamic properties stored into log4net’s global context from code and then access them from the XML configuration file. This is useful in the case where dynamic configuration of log4net is needed.
My Case: I have been building console application that will run nightly to sync some integration records and I wanted to setup logging in order to see that status of the job and gather some reporting information (counts, time run, etc). There was a catch though this process would run multiple times in a night but each time for a different customer. This would make it difficult to read the logs for a particular customer as all I would have to go on is the file date and time.
I needed a way to break my log files into different customers yet retain the rolling file appender features of log4net. My first pass at with was to configure log4net using the basic configurator all in code and create the appender, with a dynamic file name, and set the level of the logger programitacally. This was not my preferred way but was my only hope to getting the application out of developement. Then I found how to set properties into log4net’s global context and access them through the configuration file. I did run into a small problem that my app.config file was not being read in so I had to add these two variable to my assembly.
[assembly: log4net.Config.XmlConfigurator(Watch = true)] [assembly: log4net.Config.Repository]
My goal was to make the file name dynamic based on the CustomerID passed into the application. Please not the file tag as it is the ticket to my case.
<log4net>
<root>
<level value="INFO" />
<appender-ref ref="RollingLogFileAppender" />
</root> <!-- New Log File once per execution -->
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="logs\logFile_%property{BrokerID}.txt" /> <!-- Awesomeness -->
<appendToFile value="false" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="50GB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
</log4net>
Here is a sample of my log4net configuration section. Please note the file tag and type attribute to be log4net.Util.PatternString. The pattern of the value is important to, it must be %property{property_name} to get the right replacement. This is the ticket to dynamic values.
private static void InitLogger()
{
//This is freaking awesome, put a property into the log4net context and using the
// log4net.Util.PatternString type you can dynamically set values for the logging context from code.
log4net.GlobalContext.Properties["CustomerID"] = (CustomerID!= 0) ? CustomerID.ToString() : "Error";
}
Here is an example of my small InitLogger. This method is the very first item to be called when the main routine starts up. All that needs to be done now is get a logger and start logging. A file will be created based on the CustomerID which in this case is retrieved from the command line arguments before InitLogger is called. If no CustomerID is passed in than the file will be to logFile_Error.txt
private static ILog Logger; static void Main(string[] args)
{
if (args.Length > 0)
CustomerID= Util.GetInt(args[0]); InitLogger();
Logger = LogManager.GetLogger("Process");
}
Pretty cool I think, I hope this saves people some headaches. I wish I would have found this a few days ago. Oh well it is to my benefit to learn. Happy coding.
Posted in: programming problems and solutions | Tags: log4net dynamic dynamic properties dynamic property xml configuration configurator programitacallyHow To Dynamically Include Files in ASP.NET
In ASP.NET, the Response object provides a new method named WriteFile. You can use the WriteFile method to write the specified file directly to an HTTP content output stream.
If you only want to write the content of a file to the browser, you can accomplish this in just one statement. If you want to manipulate the file before you send it to the browser, refer to the References section for information about basic file input/output in .NET.
In ASP.NET, you can either write inline code or write code in the code-behind module. This article presents an inline code sample that opens a file and writes the file's content to the browser.
Steps to Create the Sample
- Open Microsoft Visual Studio .NET.
- From the File menu, point to New, and then click Project.
- In the New Project dialog box, click Visual Basic Projects under Project Types. Under Templates, click ASP.NET Web Application.
- Switch to the HTML code editor for the .aspx page that is created by default. Replace the existing code with the following code:
<%@ Page Language="vb" AutoEventWireup="false"%> <html> <body> <% Response.WriteFile ("Yourfile.inc") %> </body> </html> - Replace "Yourfile.inc" in the Response.WriteFile statement with the name of an include file that contains some HTML or client-side script.
- Add "Yourfile.inc" to the project.
- Browse to the .aspx file. Note that the content of your file is written to the browser.
Troubleshooting
- Server-side code in the dynamically included file is displayed on the client browser.
The dynamically included file may contain any client-side code, including HTML and JavaScript. If that file contains any server-side code, the server-side code is sent to the client browser as plain text and is visible if you view the source of the page that is displayed in the browser. Note that ASP.NET does not process server-side script in the dynamically included file. This is because all of the ASP.NET code has already run before it includes the file; thus, the server does not return to read anything for server-side processing again. - If you use Response.Write or Response.WriteFile statements in a code-behind module, these statements write the information before any HTML tags. The same behavior occurs if you use inline <SCRIPT> tags with the RUNAT="Server" attribute.
Because the code-behind modules are compiled first, all of the output that is generated by Response.Write, Response.WriteFile, or inline server-side <SCRIPT> tags appears before any HTML tags when the HTML output is sent to the browser. This problem does not occur when you use Response.Write statements in classic ASP-style tags.
Go with C# 4.0’s dynamic
In the case of dynamic, another frequent comment is that a statically-typed language should not try to look like a dynamic language. Well, I just don’t believe in that distinction.
Being dynamic is a trait that a language can have, and some have it more than others. But as soon as a language has a dictionary type or indexers, and most modern languages do, it starts having dynamicity. What people call a dynamic language is just one where it’s the only available type.
Now there is type safety of course, but to me that’s a different feature that is not as coupled with “statically-typed-ness” as we usually tend to think. Case in point, many modern JavaScript engines analyze the code in order to apply many of the optimization techniques that static languages have been applying at compile-time.
So just how dynamic was C# before 4.0? Well, there are dictionaries and indexers, as I’ve said, but there are also other interesting and less known features such as custom type descriptors. Go look them up if you don’t know about them. Type descriptors are for example used to provide a level of indirection between a design surface and the components being edited.
But type descriptors can also be built completely dynamically and decide to expose a completely virtual object model that is entirely built at runtime. Of course, the client code for that object has to go through the right APIs to make use of that quasi-dynamic model. And of course those APIs are not simple. Implementing a custom type descriptor in itself is not exactly trivial.
If anything, the dynamic keyword is going to provide a friendlier syntax for this sort of thing. One problem is that it has no relationship whatsoever with custom type descriptors.
So I thought I’d try to bridge that gap. How can we take a type that exposes a custom type descriptor, such as DataRowView, and transform that into something that plays nice with the dynamic keyword? What we want to be able to write is something like the following:
var table = new DataTable("People");
table.Columns.Add("FirstName", typeof(string));
table.Columns.Add("LastName", typeof(string));
table.Columns.Add("Children", typeof(int));
table.LoadDataRow(
new object[] {"Bertrand", "Le Roy", 2},
LoadOption.OverwriteChanges);
var tableView = new DataView(table);
dynamic dynRecord =
new TypeDescriptorDynamicWrapper(tableView[0]);
Console.WriteLine("{0} {1} has {2} children.",
dynRecord.FirstName,
dynRecord.LastName,
dynRecord.Children);
To do that, I built the TypeDescriptorDynamicWrapper that you see being used above. What is does is pretty simple, as it just inherits from DynamicObject and implements TryGetMember as follows:
public override bool TryGetMember(
GetMemberBinder binder, out object result) {
var name = binder.Name; var property = _properties.Find( p => p.Name.Equals(name, binder.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)); if (property == null) { result = null; return false; } result = property.GetValue(
_descriptor.GetPropertyOwner(null)); return true; }
As you can see, the method just finds the right property on the type descriptor and delegates to it if it finds it. I didn’t implement the setting of properties but it would be fairly easy to do so.
Using that simple wrapper, the program above just works and displays:
Bertrand Le Roy has 2 children.
That was easy. Now what about the reverse, getting any dynamic object to expose a custom type descriptor?
Well, that’s where things get tricky.
The dynamic capabilities of C# 4.0 are targeted at two things:
- Providing syntactic sugar for getting to dynamic members that looks like accessing statically-defined ones.
- An easy way to create dynamic types by implementing a form of method_missing.
But there is one thing that exists in DLR but didn’t make it to C# yet, which is the ability to easily reflect on dynamic objects (other than by using the #1 syntactic sugar above).
For example, in JavaScript, a.foo and a[“foo”] are exactly the same thing, which enables easy reflection: you can enumerate the members of an arbitrary object and do stuff like a[someStringVariable].
Doing the same thing with C# on dynamic objects is much more difficult. The equivalent of a.foo is easy, but not the equivalent of a[someStringVariable].
Forget about using reflection, it doesn’t work on dynamic objects because dynamic really is a compiler trick. There is no such thing as a “dynamic” type to reflect on. It’s a keyword that tells the compiler to relax type-checking and generate code to access those dynamic members at runtime. If you try to reflect on an instance of one of the dynamic-friendly type, such as ExpandoObject, you’ll see the statically-defined members of that type, but not the dynamic ones. In a way, you’re looking at the messenger instead of the message.
This is a problem because in order to wrap an arbitrary dynamic object into a custom type descriptor, we need to be able to reflect on the dynamic members of that object.
To solve the problem, and with some help from the nice folks who are building the DLR, I compiled a simple program that sets and gets a property on a dynamic object, an then I looked at the generated code from Reflector (“luckily”, Reflector is not yet aware of dynamic and shows the generated code instead of something closer to the actual code you wrote).
I was then able to refactor that code and replace the string constants for the accessed member with a method parameter, thus creating a generic way to access dynamic object properties:
public static object GetValue(
object dyn, string propName) {
// Warning: this is rather expensive,
// and should be cached in a real app var GetterSite =
CallSite<Func<CallSite, object, object>>
.Create( new CSharpGetMemberBinder(propName, dyn.GetType(), new CSharpArgumentInfo[] { new CSharpArgumentInfo(
CSharpArgumentInfoFlags.None, null) })); return GetterSite.Target(GetterSite, dyn); } public static void SetValue(
object dyn, string propName, object val) {
// Warning: this is rather expensive,
// and should be cached in a real app var SetterSite =
CallSite<Func<CallSite, object, object, object>>
.Create( new CSharpSetMemberBinder(propName, dyn.GetType(), new CSharpArgumentInfo[] { new CSharpArgumentInfo(
CSharpArgumentInfoFlags.None, null), new CSharpArgumentInfo(
CSharpArgumentInfoFlags.LiteralConstant | CSharpArgumentInfoFlags.UseCompileTimeType,
null) })); SetterSite.Target(SetterSite, dyn, val); }
Once we have that, implementing the custom type provider is relatively straightforward. The only part that is not immediately obvious is how to enumerate the properties of the dynamic object.
This is done as follows. Dynamic objects implement IDynamicMetaObjetProvider, which has a GetMetaObject method, which returns a DynamicMetaObject object on which you can call GetDynamicMemberNames to get the list of members.
We can now take any dynamic object and for example present it in a property grid, which is one of those components that know how to handle custom type descriptors but not the new dynamic objects:
dynamic person = new ExpandoObject(); person.FirstName = "Bertrand"; person.LastName = "Le Roy"; person.Children = 2; propertyGrid1.SelectedObject =Posted in: asp.net | Tags: c# dynamic data 4.0 dynamic api datarowview typedescriptordynamicwrapper dynamicobject trygetmember
new DynamicTypeDescriptorWrapper(person);
Features for COM interop in C# 4.0
Dynamic lookup as well as named and optional parameters greatly improve the experience of interoperating with COM APIs such as the Office Automation APIs. In order to remove even more of the speed bumps, a couple of small COM-specific features are also added to C# 4.0.
Dynamic import
Many COM methods accept and return variant types, which are represented in the PIAs as object. In the vast majority of cases, a programmer calling these methods already knows the static type of a returned object from context, but explicitly has to perform a cast on the returned value to make use of that knowledge. These casts are so common that they constitute a major nuisance.
In order to facilitate a smoother experience, you can now choose to import these COM APIs in such a way that variants are instead represented using the type dynamic. In other words, from your point of view, COM signatures now have occurrences of dynamic instead of object in them.
This means that you can easily access members directly off a returned object, or you can assign it to a strongly typed local variable without having to cast. To illustrate, you can now say
excel.Cells[1, 1].Value = "Hello";
instead of
((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello";
and
Excel.Range range = excel.Cells[1, 1];
instead of
Excel.Range range = (Excel.Range)excel.Cells[1, 1];
Compiling without PIAs
Primary Interop Assemblies are large .NET assemblies generated from COM interfaces to facilitate strongly typed interoperability. They provide great support at design time, where your experience of the interop is as good as if the types where really defined in .NET. However, at runtime these large assemblies can easily bloat your program, and also cause versioning issues because they are distributed independently of your application.
The no-PIA feature allows you to continue to use PIAs at design time without having them around at runtime. Instead, the C# compiler will bake the small part of the PIA that a program actually uses directly into its assembly. At runtime the PIA does not have to be loaded.
Omitting ref
Because of a different programming model, many COM APIs contain a lot of reference parameters. Contrary to refs in C#, these are typically not meant to mutate a passed-in argument for the subsequent benefit of the caller, but are simply another way of passing value parameters.
It therefore seems unreasonable that a C# programmer should have to create temporary variables for all such ref parameters and pass these by reference. Instead, specifically for COM methods, the C# compiler will allow you to pass arguments by value to such a method, and will automatically generate temporary variables to hold the passed-in values, subsequently discarding these when the call returns. In this way the caller sees value semantics, and will not experience any side effects, but the called method still gets a reference.
Open issues
A few COM interface features still are not surfaced in C#. Most notably these include indexed properties and default properties. As mentioned above these will be respected if you access COM dynamically, but statically typed C# code will still not recognize them.
There are currently no plans to address these remaining speed bumps in C# 4.0.
Posted in: programming | Tags: c# .net 4.0 dynamic c# 4.0 dynamic import interop open issues omitting ref