I want to write a very simple logging method. It will basically wrap WriteLine(...). It should take any number of parameters. The first will either be a StreamWriter object or null. If the first object is null then it should use Console.Writeline()... otherwise the StreamWriter object.
I have seen that I should perhaps be using the params ... method parameter keyword, à la:
private static void MyLog(params object[] list) {
if (list.Length <= 0) {
throw new ArgumentException("Parameter list is empty.");
}
if (list.Length <= 2)
{
throw new ArgumentException("Parameter list is too short.");
}
var log = (StreamWriter) list[0];
if (log != null) {
log.WriteLine(list.Skip(1).Take(list.Length - 1));
} else {
Console.WriteLine(list.Skip(1).Take(list.Length - 1));
}
}
This is called as:
try {
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
var dirPath = Path.GetDirectoryName(exePath);
var logFile = dirPath + "\\myLog.log";
_log = File.AppendText(logFile);
_log.AutoFlush = true;
MyLog(_log, "----- START ----- {0:yyyy-MM-dd HH:mm:ss} -----", DateTime.Now);
} catch (Exception e) {
_log = null;
MyLog(null, e.Message);
}
...
MyLog(_log, "{0}:AD property {1} is null", username, property);
...
I was really hoping that the list.Skip(1).Take(list.Length - 1) construct would do an "array slice" and feed the 1..nth list objects to WriteLine and that it would do the right thing. Instead I get a stream of
System.Linq.Enumerable+<TakeIterator>d__25`1[System.Object]
How does one correctly wrap Writeline for such things?
Is there a better way to handle this sort of string interpolation logging to file or console?
The general idea for what you want already exists in the framework, albeit with a somewhat different API.
Take a look at the System.Diagnostics.Trace type. It has a WriteLine() method, and it works by letting you attach one or more TraceListener objects, of which the framework provides ConsoleTraceListener and TextWriterTraceListener (for files) out of the box, as well as others.
You can also make your own TraceListener to do things like log to a database or re-implement existing listeners to add features like automatically including timestamp or path information.
Sadly, Trace.WriteLine() is missing some of the expected overloads. This was more of problem until recently, but now that we have interpolated strings it's no big deal.
In this case, you would build your own TraceListener type (inherit from TextWriterTraceListener and most of the work is done for you) which attempts to append to a log file, but writes to the Console if an exception is thrown. Later on, the code just looks like this, and you get all of the features you wanted:
Trace.WriteLine($"{username}:AD property {property} is null");
At very least, it's much better practice to provide overloads to decide whether to use a streamwriter or console, like this:
private static void MyLog(string format, params object[] list)
{
Console.WriteLine(format, list);
}
private static void MyLog(StreamWriter log, string format, params object[] list)
{
log.WriteLine(format, list);
}
Again, that is MUCH better practice. But if you really want your existing code, replace the Take() calls with ToArray(). Then you match up with what the existing WriteLine() overloads expect.
private static void MyLog(StreamWriter sw, string format, params object[] args)
{
if (sw == null)
Console.WriteLine(format, args);
else
sw.WriteLine(format, args);
}
If you know that your first parameter is a StreamWriter, change the signature to reflect that:
private static void MyLog(StreamWriter log, params object[] list) {
If you know the what type the rest of the objects are, I'd type them too.
The number of elements in list will never be less than 0:
if (list.Length <= 0) {
The Take method is only needed if you want a subset of elements from the beginning, not the rest of them, and since you already skipped one, you just want the rest:
list.Skip(1)
The above, however, is not necessary, since we changed the signature of your method, so you just want your full list array.
The WriteLine method doesn't know how you want the array of unknown objects formatted. Even if it was a string[], I'm not sure it would know what to do with it. If we assume that it's a string[], you could do the following:
WriteLine(list.Aggregate((current, next) => current + Environment.NewLine + next))
If that doesn't help, please specify which content you expect, and how you'd like it formatted.
Related
When logging in C#, how can I learn the name of the method that called the current method? I know all about System.Reflection.MethodBase.GetCurrentMethod(), but I want to go one step beneath this in the stack trace. I've considered parsing the stack trace, but I am hoping to find a cleaner more explicit way, something like Assembly.GetCallingAssembly() but for methods.
Try this:
using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
one-liner:
(new System.Diagnostics.StackTrace()).GetFrame(1).GetMethod().Name
It is from Get Calling Method using Reflection [C#].
In C# 5, you can get that information using caller info:
//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "")
{
Console.WriteLine(callerName + "called me.");
}
You can also get the [CallerFilePath] and [CallerLineNumber].
You can use Caller Information and optional parameters:
public static string WhoseThere([CallerMemberName] string memberName = "")
{
return memberName;
}
This test illustrates this:
[Test]
public void Should_get_name_of_calling_method()
{
var methodName = CachingHelpers.WhoseThere();
Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}
While the StackTrace works quite fast above and would not be a performance issue in most cases the Caller Information is much faster still. In a sample of 1000 iterations, I clocked it as 40 times faster.
A quick recap of the 2 approaches with speed comparison being the important part.
http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx
Determining the caller at compile-time
static void Log(object message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
// we'll just use a simple Console write for now
Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}
Determining the caller using the stack
static void Log(object message)
{
// frame 1, true for source info
StackFrame frame = new StackFrame(1, true);
var method = frame.GetMethod();
var fileName = frame.GetFileName();
var lineNumber = frame.GetFileLineNumber();
// we'll just use a simple Console write for now
Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}
Comparison of the 2 approaches
Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms
So you see, using the attributes is much, much faster! Nearly 25x
faster in fact.
We can improve on Mr Assad's code (the current accepted answer) just a little bit by instantiating only the frame we actually need rather than the entire stack:
new StackFrame(1).GetMethod().Name;
This might perform a little better, though in all likelihood it still has to use the full stack to create that single frame. Also, it still has the same caveats that Alex Lyman pointed out (optimizer/native code might corrupt the results). Finally, you might want to check to be sure that new StackFrame(1) or .GetFrame(1) don't return null, as unlikely as that possibility might seem.
See this related question:
Can you use reflection to find the name of the currently executing method?
In general, you can use the System.Diagnostics.StackTrace class to get a System.Diagnostics.StackFrame, and then use the GetMethod() method to get a System.Reflection.MethodBase object. However, there are some caveats to this approach:
It represents the runtime stack -- optimizations could inline a method, and you will not see that method in the stack trace.
It will not show any native frames, so if there's even a chance your method is being called by a native method, this will not work, and there is in-fact no currently available way to do it.
(NOTE: I am just expanding on the answer provided by Firas Assad.)
As of .NET 4.5 you can use Caller Information Attributes:
CallerFilePath - The source file that called the function;
CallerLineNumber - Line of code that called the function;
CallerMemberName - Member that called the function.
public void WriteLine(
[CallerFilePath] string callerFilePath = "",
[CallerLineNumber] long callerLineNumber = 0,
[CallerMemberName] string callerMember= "")
{
Debug.WriteLine(
"Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}",
callerFilePath,
callerLineNumber,
callerMember);
}
This facility is also present in ".NET Core" and ".NET Standard".
References
Microsoft - Caller Information (C#)
Microsoft - CallerFilePathAttribute Class
Microsoft - CallerLineNumberAttribute Class
Microsoft - CallerMemberNameAttribute Class
Obviously this is a late answer, but I have a better option if you can use .NET 4.5 or newer:
internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}
This will print the current Date and Time, followed by "Namespace.ClassName.MethodName" and ending with ": text".
Sample output:
6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized
Sample use:
Logger.WriteInformation<MainWindow>("MainWindow initialized");
Note that doing so will be unreliable in release code, due to optimization. Additionally, running the application in sandbox mode (network share) won't allow you to grab the stack frame at all.
Consider aspect-oriented programming (AOP), like PostSharp, which instead of being called from your code, modifies your code, and thus knows where it is at all times.
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
return GetCallingMethod("GetCallingMethod");
}
/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
string str = "";
try
{
StackTrace st = new StackTrace();
StackFrame[] frames = st.GetFrames();
for (int i = 0; i < st.FrameCount - 1; i++)
{
if (frames[i].GetMethod().Name.Equals(MethodAfter))
{
if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
{
str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
break;
}
}
}
}
catch (Exception) { ; }
return str;
}
Maybe you are looking for something like this:
StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name
MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name
private static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
private static Type GetCallingType()
{
return new StackFrame(2, false).GetMethod().DeclaringType;
}
A fantastic class is here: http://www.csharp411.com/c-get-calling-method/
Another approach I have used is to add a parameter to the method in question. For example, instead of void Foo(), use void Foo(string context). Then pass in some unique string that indicates the calling context.
If you only need the caller/context for development, you can remove the param before shipping.
For getting Method Name and Class Name try this:
public static void Call()
{
StackTrace stackTrace = new StackTrace();
var methodName = stackTrace.GetFrame(1).GetMethod();
var className = methodName.DeclaringType.Name.ToString();
Console.WriteLine(methodName.Name + "*****" + className );
}
Extra information to Firas Assaad answer.
I have used new StackFrame(1).GetMethod().Name; in .net core 2.1 with dependency injection and I am getting calling method as 'Start'.
I tried with [System.Runtime.CompilerServices.CallerMemberName] string callerName = ""
and it gives me correct calling method
We can also use lambda's in order to find the caller.
Suppose you have a method defined by you:
public void MethodA()
{
/*
* Method code here
*/
}
and you want to find it's caller.
1. Change the method signature so we have a parameter of type Action (Func will also work):
public void MethodA(Action helperAction)
{
/*
* Method code here
*/
}
2. Lambda names are not generated randomly. The rule seems to be: > <CallerMethodName>__X
where CallerMethodName is replaced by the previous function and X is an index.
private MethodInfo GetCallingMethodInfo(string funcName)
{
return GetType().GetMethod(
funcName.Substring(1,
funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1)
);
}
3. When we call MethodA the Action/Func parameter has to be generated by the caller method.
Example:
MethodA(() => {});
4. Inside MethodA we can now call the helper function defined above and find the MethodInfo of the caller method.
Example:
MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;
will be enough, I think.
So I have a number of different potential object that can output data (strings). What I want to be able to do, is to Run a generic Output.WriteLine function, with the potential arguments that define where you want it to be outputted to. What I've got for code -
//Defined in static class Const
public enum Out : int { Debug = 0x01, Main = 0x02, Code = 0x04 };
static class Output
{
private static List<object> RetrieveOutputMechanisms(Const.Out output)
{
List<object> result = new List<object>();
#if DEBUG
if (bitmask(output, Const.Out.Debug))
result.Add(1);//Console); //I want to add Console here, but its static
#endif
if (bitmask(output, Const.Out.Main))
if (Program.mainForm != null)
result.Add(Program.mainForm.Box);
if (bitmask(output, Const.Out.Code))
if (Program.code!= null)
result.Add(Program.code.Box);
return result;
}
public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
{
Console.WriteLine(
List<object> writers = RetrieveOutputMechanisms(output);
foreach (object writer in writers)
writer.WriteLine(str, color);
}
}
The point of this, is that the output destinations are not always existent, as they are on forms that may or may not exist when these calls are called. So the idea is to determine which ones you're trying to print to, determine if it exists, add it to the list of things to be printed to, then loop through and print to all of them if they implement the "WriteLine" method.
The two problems that I've come across, are
That Console is a static class, and can't properly (as far as my knowledge goes) be added to the object list.
I don't know how I can assert that the objects in the list define WriteLine, and cast them to something that would apply to more than one base Type. Assuming I can get Console to work properly in this scheme, that would be the obvious problem, its not of the same base type as the actual Boxes, but also, if I had something that wasnt a Box, then it would be lovely to do something like
foreach (object writer in writers)
.WriteLine(str, color)
so that I wouldn't have to individually cast them.
The bigger reason that I don't simply WriteLine from the RetrieveOutputMechanisms function, is that I want this to cover more than just WriteLine, which means that I would need to copy the bitmask code to each function.
EDIT: I realise that adding public properties to Program is a bad idea, if you know how I can avoid it (the necessity coming from needing to be able to access any WriteLine-able form objects that come and go, from anywhere), by all means please elaborate.
One way would be to use an Action (a delegate) and store those in your List. This will work for Console and any other class as you can easily write a lambda (or a 2.0 delegate) to map your output variables to the right parameters in the called method. There will be no need for casting. It could work something like this:
(This assumes you are using C# 3.5 or later but you can do all this in anything from 2.0 and on using delegates)
static class Output
{
private static List<Action<string, Color>> RetrieveOutputMechanisms(Const.Out output)
{
List<Action<string, Color>> result = new List<string, Color>();
#if DEBUG
if (bitmask(output, Const.Out.Debug))
result.Add((s, c) => Console.WriteLine(s, c)); //I want to add Console here, but its static
#endif
if (bitmask(output, Const.Out.Main))
if (Program.mainForm != null)
result.Add((s, c) => Program.mainForm.Box.WriteLine(s, c));
if (bitmask(output, Const.Out.Code))
if (Program.code!= null)
result.Add((s, c) => Program.code.Box.WriteLine(s, c));
return result;
}
public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
{
var writers = RetrieveOutputMechanisms(output);
foreach (var writer in writers)
writer(str, color);
}
}
(edit to add)
You could change this more significantly to allow classes to "register" to be able to do the writing for a specific "output mechanism" in the Output class itself. You could make Output a singleton (there are arguments against doing that but it would be better than sticking public static variables in your main program for this purpose). Here is an example with more significant changes to your original class:
public sealed class Output
{
private Dictionary<Out, Action<string, Color>> registeredWriters = new Dictionary<Out, Action<string, Color>>();
public static readonly Output Instance = new Output();
private void Output() { } // Empty private constructor so another instance cannot be created.
public void Unregister(Out outType)
{
if (registeredWriters.ContainsKey(outType))
registeredWriters.Remove(outType);
}
// Assumes caller will not combine the flags for outType here
public void Register(Out outType, Action<string, Color> writer)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (registeredWriters.ContainsKey(outType))
{
// You could throw an exception, such as InvalidOperationException if you don't want to
// allow a different writer assigned once one has already been.
registeredWriters[outType] = writer;
}
else
{
registeredWriters.Add(outType, writer);
}
}
public void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
{
bool includeDebug = false;
#if DEBUG
includeDebug = true;
#endif
foreach (var outType in registeredWriters.Keys)
{
if (outType == Const.Out.Debug && !includeDebug)
continue;
if (bitmask(output, outType))
registeredWriters[outType](str, color);
}
}
}
Then elsewhere in your program, such as in the form class, to register a writer, do:
Output.Instance.Register(Const.Out.Main, (s, c) => this.Box.WriteLine(s, c));
When your form is unloaded you can then do:
Output.Instance.Unregister(Const.Out.Main);
Then another way would be to not use a singleton. You could then have more than one Output instance for different purposes and then inject these into your other classes. For instance, change the constructor for your main form to accept an Output parameter and store this is an object variable for later use. The main form could then pass this on to a child form that also needs it.
If your objects that have data that need to be written behave like this:
A always writes to console and log
B always writes to log
C always writes to console
For all data, then your best bet would be to declare an interface and have each of them implement the interface method for output. Then, in your calling code, declare them not as their actual types but instead of type IOutput or whatever interface u call that has the method. Then have two helper methods, one for actually outputting to console and one for actually outputting to a log file. A would call both helpers, B and C their respective ones.
If, on the other hand, your objects will write to various logs at differing times:
A, B and C sometimes write to console and sometimes to log, depending on some property
Then I would recommend you create an event handler for when a class wants something to be written. Then, have the logic that discerns what writes to console and what writes to log in a listener class and attach the appropriate ones to that output event. That way, you can keep the logic about what is being written to where in classes that encapsulate just that functionality, while leaving the A, B and C classes free of dependencies that may come to bite you down the road. Consider having a monolithic method as you describe which uses a bitmask. As soon as the behavior of A, B or C's logging changes, or if you need to add a new output, you suddenly need to worry about one class or method affecting all of them at once. This makes it less maintainable, and also trickier to test for bugs.
MethodInfo methodname = typeof(object).GetMethod("MethodA");
Then just use a if statement to check if methodname is null or not.
How do I know the log the last property that is null?
For example,
var a = "somevalue";
......
......
if(a == null)
{
Log.Error(MethodBase.GetCurrentMethod().Name + "Property : a is null");
//blah blah
}
Like how I use the reflection to get the current method name, there should be some means by which I can log the latest local variables (or a property or fields)
that is being compared ? I use, log4net by the way to log the errors.
1) Is there any method to achieve this or should we manually log it?
2) Is there any custom method that prints the class -> MethodName -> Propertyname(or FieldName) that is null?
Thanks for your time in advance.
As mentioned by #fsimonazzi, "a" would be a local variable.
That being said there is still no way to examine the current compare operation as in MSIL there is no formal concept of an IF block - only conditional jumps.
If you wanted to get really crazy with the reflection, you may be able to find the current executing instruction and look around near that for a variable, but even then, you will not find the name - only a reference - as names are only used prior to compilation.
Either way, reflection is not going to help you here.
Instead, try using Exceptions - specifically ArgumentNullException. This body of code would become:
void doStuff(string param1, int param2)
{
if (param == null)
throw new ArgumentNullException("param1", "param1 must not be null");
if (param2 < 0)
throw new ArgumentOutOfRangeException("param2", "param2 should be non-negative.");
//method body
}
then, when you call the method, you can catch the exception and log it - no matter what it may be.
public static void Main(string[] args)
{
try
{
doStuff(null, 3);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Tools like FxCop can help make sure that you are properly validating each parameter.
Properties are actually implemented as methods, so reflection could help you there. If, for example, you were validating in a property and wanted to log the position automatically, you could.
private object _cachedObject = null;
public object CachedObject
{
get
{
if (_cachedObject == null)
{
log(MethodBase.GetCurrentMethod().Name, "creating cached object");
_cachedObject = createCachedObject();
}
return _cachedObject;
}
}
The .Net Framework 4.5 also brings with it a new attribute that can be used to replace the MethodBase.GetCurrentMethod().Name construct you are using to get the method name. See [CallerMemberNameAttribute][3].
I was writing some try-catch blocks for various methods today, and thought to myself it would be good to have utility method which would automatically call the method again for a number of times specified in a parameter, at a certain time.
However, I thought to myself, the method/property etc which will cause an exception will be at the top of the stacktrace (do property calls get put on the stacktrace?) in a single threaded application (so an application with no code relating to threading). So I can simply get the method name at the top and dynamically call it again.
So I would have code like:
string s = StackTrace.GetFrame(0).GetMethodName; (I can't remember the exact syntax).
With this method, I can execute it using an activator or one of several other ways.
But in a multi-threaded application, I could have several methods firing at once and I wouldn't know which one finishes first/last. So I can't expect a method for which I write a try-catch block to be at the top of the stack.
How would I go about achieving this?
Please don't do this. It's a really, really, really, really, really bad idea.
Maybe not as bad as deleting files randomly, if the hard drive runs out of room - but just about as bad.
While I question the need for an auto retrying mechanism (does randomly retrying really help you out in so many situations that you need a utility method?) - using StackTrace and Reflection is, at best, a terribly complicated solution.
Not that I suggest that anyone actually use this code, but I'd probably go with a delegate based approach to this particular problem:
public static class Extensions {
public static void Try(this Action a, int maxTries) {
new (Func<bool>(() => { a(); return true; })).Try(maxTries);
}
public static TResult Try<TResult>(this Func<TResult> f, int maxTries) {
Exception lastException = null;
for (int i = 0; i < maxTries; i++) {
try {
return f();
} catch (Exception ex) {
lastException = ex;
}
}
throw lastException;
}
}
Usage is a bit unorthodox, but fairly clear I think:
// Set a property
new Action(() => myObject.Property = 5).Try(5);
// With a return value
var count = new Func<int>(() => myList.Count).Try(3);
You can't inline a lambda to a method, but you could have a somewhat fluent interface:
Utilities.Try(
() => MyObject.Property = 5
).Repeat(5);
And multi line methods:
Utilities.Try(() => {
MyObject.Property1 = 5;
MyObject.Property2 = 6;
MyObject.Property3 = 7;
}).Repeat(5);
Mark's code is probably better, but here's mine...
If you really want to do something like this, I'd use code something like this. Yes, you still have to manually call it, but your idea of indiscriminately retrying ALL excepting methods is a really, really bad idea.
public class TryAgain
{
public delegate void CodeToTryAgain ();
public static void Repeat<E>(int count, CodeToTryAgain code) where E : Exception
{
while (count-- > 0)
{
try
{
code();
return;
}
catch (E ex)
{
Console.WriteLine("Caught an {0} : {1}", typeof(E).Name, ex.Message);
// ignoring it!
}
}
}
}
And then you'd call your failing method, ThrowTwice, or whatever you want to do, like this:
TryAgain.Repeat<MyException>(5, delegate()
{
ThrowTwice();
});
In this example, the Repeat method will ignore all exceptions of type MyException, trying to call ThrowTwice up to 5 times...
You can add your own sleeping and time-outs, and whatever.
A lot of my C# code follows this pattern:
void foo(string param1, string param2, string param3)
{
try
{
// do something...
}
catch(Exception ex)
{
LogError(String.Format("Error in foo(param1={0}, param2={1}, param3={2}), exception={3}", param1, param2, param3, ex.Message));
}
}
Is there a way in .NET to get a Key/Value list of the parameters to a function so that I can call another function to construct my error logging string?
OR
Do you have a more generic / better way of doing this?
You could use Reflection and the convention that you must pass the parameters to the LogError with the right order:
private static void MyMethod(string s, int x, int y)
{
try
{
throw new NotImplementedException();
}
catch (Exception ex)
{
LogError(MethodBase.GetCurrentMethod(), ex, s, x, y);
}
}
private static void LogError(MethodBase method, Exception ex, params object[] values)
{
ParameterInfo[] parms = method.GetParameters();
object[] namevalues = new object[2 * parms.Length];
string msg = "Error in " + method.Name + "(";
for (int i = 0, j = 0; i < parms.Length; i++, j += 2)
{
msg += "{" + j + "}={" + (j + 1) + "}, ";
namevalues[j] = parms[i].Name;
if (i < values.Length) namevalues[j + 1] = values[i];
}
msg += "exception=" + ex.Message + ")";
Console.WriteLine(string.Format(msg, namevalues));
}
You could use aspect oriented programming with PostSharp (have a look at http://www.postsharp.org, and the tutorial at http://www.codeproject.com/KB/cs/ps-custom-attributes-1.aspx). Basically you could do something like this:
public class LogExceptionAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgs eventArgs)
{
log.error("Exception occurred in method {0}", eventArgs);
}
}
[LoggingOnExceptionAspect]
public foo(int number, string word, Person customer)
{
// ... something here throws an exception
}
Perhaps not quite what you want, but I'm sure it can be adapted to suit your needs.
No there isn't a way to do this.
The normal practice is to not catch exceptions unless you can handle them.
I.e. you would normally only catch exceptions and log them in a top-level exception handler. You will then get a stack trace, but won't of course get details of all the parameters of all method calls in the stack.
Obviously when debugging you want as much detail as possible. Other ways to achieve this are:
Use Debug.Assert statements liberally to test assumptions you are making.
Instrument your application with logging that can be activate selectively. I use Log4Net, but there are also other alternatives, including using the System.Diagnostics.Trace class.
In any case, if you do catch exceptions only to log them (I'd do this at a tier boundary in an n-tier application, so that exceptions are logged on the server), then you should always rethrow them:
try
{
...
}
catch(Exception ex)
{
log(ex);
throw;
}
When I have done this I just created a generic dictionary for the logging.
I have this LogArgs class. And logging in a base class that I call when I have an exception.
public class LogArgs
{
public string MethodName { get; set; }
public string ClassName { get; set; }
public Dictionary<string, object> Paramters { get; set; }
public LogArgs()
{
this.Paramters = new Dictionary<string, object>();
}
}
Then at the start of every method I do
LogArgs args = new LogArgs { ClassName = "ClassName", MethodName = "MethodName" };
args.Paramters.Add("Param1", param1);
args.Paramters.Add("Param2", param2);
args.Paramters.Add("Param3", param3);
base.Logger.MethodStartLog(args);
When I have an error I log it this way.
base.Logger.LogError(args, ex);
You could use a similar style of constructing the message, but add the params keyword in your LogError method to handle the arguments. For example:
public void LogError(string message, params object[] parameters)
{
if (parameters.Length > 0)
LogError(string.Format(message, parameters));
else
LogError(message);
}
This is little dated post but just in case someone comes across this like I did - I solved this issue by using PostSharp.
It's not practically free though. The Express license (downloadable via NuGet in VS) allows you to decorate your method with [Log] attribute and then choose your already configured mechanism for logging, like log4net nLog etc. Now you will start seeing Debug level entries in your log giving parameter details.
With express license I could only decorate a maximum of 50 methods in my project. If it fits your needs you're good to go!
Late to the party but I did something along these lines a year or so ago:
Github Repo
The idea of this setup is much like what your after, but with the ability to hook it up globally, there is more code than I would like there but it works and once plugged in, works for what your after.
If you take a quick look at the ProxyLogger.cs, consider this a wrapper, it will encapsulate any method it is given and execute it while handling the logging of the error as set here. This can then be setup with dependency injection for anything and everything you wish to log, e.g.:
public void ConfigureServices(HostBuilderContext hostBuilder, IServiceCollection services)
{
services.AddOptions();
services.AddSingleton<IHostedService, HostedService>();
services.AddSingleton<IMyClass, MyClass>();
// Logging added for both the hosted service and the example class
services.Decorate<IMyClass, ProxyLogger<IMyClass>>();
services.Decorate<IHostedService, ProxyLogger<IHostedService>>();
}
You register your services as normal, but on top of that, you can decorate them with the proxy logger to handle the execution and log the details before, after, on failure etc, with FULL params.
I was obsessed with this for a while and this is as best as I could get it, but it works really well.
There are scenarios of a few parameters or Large number of parameters...
Few parameters, without much ado, better write them as part of the logging/exception message.
In large parameters, a multi-layer application would be using ENTITIES ( like customer, CustomerOrder...) to transfer data between layers. These entities should implement
override ToString() methods of class Object, there by,
Logmessage(" method started " + paramObj.ToString()) would give the list of data in the object..
Any opinions? :)
thanks