So, this example is contrived to try to give a simple view of a much larger system I am trying to modify (namely, Orchard CMS). As such, it may not be perfect.
I am trying to create a logging system that is managed through settings. The problem I'm running into is that retrieving the settings causes logging to occur. Here's a simple example that hopefully describes the problem:
static void Main(string[] args)
{
string[] messages = "this is a test. but it's going to be an issue!".Split(' ');
Parallel.ForEach(messages, Log);
Console.ReadLine();
}
public static void Log(string message)
{
Console.WriteLine(GetPrefix() + message);
}
public static string GetPrefix()
{
Log("Getting prefix!");
return "Prefix: ";
}
This is an obvious StackOverflowException. However, how can I resolve it? I can't just disable the logging until I get the response from GetPrefix, because I may miss logs. (In fact, in this simple example, I miss all but the first.)
static void Main(string[] args)
{
string[] messages = "this is a test. but it's going to be an issue!".Split(' ');
Parallel.ForEach(messages, Log);
Console.ReadLine();
}
static bool _disable = false;
public static void Log(string message)
{
if (_disable)
{
return;
}
_disable = true;
Console.WriteLine(GetPrefix() + message);
_disable = false;
}
public static string GetPrefix()
{
Log("Getting prefix!");
return "Prefix: ";
}
(^Bad.)
Note that I do not currently have control over the GetPrefix method, only the Log method.
I'm not sure if there's a way to resolve this; I may need to put the settings elsewhere (such as the config or a separate settings file). However, if anyone has ideas or suggestions, I'd be happy to try anything, as I'd prefer to leave the settings as I have them now (which is in an admin interface).
All you need to do is to disable on the current stack frame. Now you could use reflection to go over the stack frame and see if it's been called but there's a much simpler method. You have a stack frame for each thread. So make the static variable [ThreadStatic]
[ThreadStatic]
static bool _disable = false;
How does this work?
http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx
"Indicates that the value of a static field is unique for each thread."
Edit: that alone might not be enough, however. What you probably want is one static variable per TASK. Now, as tasks would be executed sequentially per thread, in this particular case I don't think it's an issue, unless loggers can potentially fail without disabling... and I'm not sure what happens in that case, but it might require you to at the very least wrap things in a try/finally block:
static void Main() //Main(string[] args)
{
string[] messages = "this is a test. but it's going to be an issue!".Split(' ');
Parallel.ForEach(messages, Log);
Console.ReadLine();
}
[ThreadStatic]
static bool _disable = false;
public static void Log(string message)
{
if (_disable)
{
return;
}
try {
_disable = true;
Console.WriteLine(GetPrefix() + message);
} finally {
_disable = false;
}
}
public static string GetPrefix()
{
Log("Getting prefix!");
return "Prefix: ";
}
Edit II: From http://msdn.microsoft.com/en-us/library/dd460712.aspx it seems that once any of a set of tasks throws an exception outside of the task delegate, you are not guaranteed execution of any remaining tasks. It's best to handle those exceptional cases in your delegate.
How about splitting the log method into:
public static void LogWithPrefix(string message)
{
var prefix = GetPrefix();
Log(prefix + message);
}
public static void Log(string message)
{
Console.WriteLine(message);
}
Related
I have a lot of static helper methods in my project and I often pass context to them as an argument. Here are two examples
private static bool SaveSetupDetails(Context context, string sftpAddress, string sftpUserName, string sftpPassword)
{
try
{
using (ISharedPreferences settings = PreferenceManager.GetDefaultSharedPreferences(context))
using (ISharedPreferencesEditor editor = settings.Edit())
{
editor.PutString("VePSFTPAddr", sftpAddress);
editor.PutString("VePSFTPUser", sftpUserName);
editor.PutString("VePSFTPPass", sftpPassword);
editor.Commit();
return true;
}
}
catch (Exception e)
{
Log.Debug("SomeTag", "SomeActivity - SaveSetupDetails threw an exception: " + e.Message);
return false;
}
}
Second example
public static bool IsCallActive(Context context)
{
AudioManager manager = (AudioManager)context.GetSystemService(Context.AudioService);
if (manager.Mode == Mode.InCall)
{
return true;
}
return false;
}
I am wondering if passing the context like this can cause the static method to hold on to it's reference and cause a memory leak. Or does it get de-referenced after the method is done executing?
Hi #Ali Zahid if you are passing context in parameters and using like the above two methods then it will get de-referenced because you haven't stored its object using static keyword in the class. Only those objects will be saved in the memory in which we have applied static keyword in front of the class name while initializing. for example
static int a = 0;
You can unregistered in references in onDestroy() safely and avoiding memory leaks.
#Override
protected void onDestroy() {
super.onDestroy();
//unregister your references.
}
:)
There is a webforms application with classes that contain lot of methods. I want to keep logs of the methods that are being called in a flexible and easy way.
I want to know which method has finally been called and some other additional info like:
input values and
result values
Crash exceptions (if there is a crash)
Currently, I am using log4net for filesystem logging like:
using log4net;
private static readonly ILog Log1 = LogManager.GetLogger("Log1");
public int DoSomething(int itemId = 0)
{
Log1.DebugFormat("[DoSomething] - Doing Something on item {0} Started", itemId );
try
{
//something..
}
catch (Exception ex)
{
Log1.Debug("[DoSomething] - Something Failed", ex);
}
Log1.DebugFormat("[DoSomething] - Doing Something on item {0} Finished", itemId );
return 0;
}
How is it possible to achieve this without writing every time these pieces of code in every method? Is there a better and automatic way?
What about the performance cost in every case?
An alternative approach would be great!
Below code should give you a starting point. It's a sample which uses console instead of log4net, but I think it's trivial to extend it to use whatever you need.
First install PostSharp nuget package. Then define new aspect:
[Serializable]
public sealed class TraceAttribute : OnMethodBoundaryAspect
{
private readonly string _argumentsFormat;
[NonSerialized]
private string _methodName;
public TraceAttribute() {
}
public TraceAttribute(string argumentsFormat) {
_argumentsFormat = argumentsFormat;
}
public override void RuntimeInitialize(MethodBase method) {
_methodName = method.Name;
}
public override void OnEntry(MethodExecutionArgs args) {
string msg = $"[{_methodName}]: entered";
if (!String.IsNullOrWhiteSpace(_argumentsFormat)) {
msg += String.Format(". Arguments:" + _argumentsFormat, args.Arguments.ToArray());
}
Console.WriteLine(msg);
}
// Invoked at runtime after the target method is invoked (in a finally block).
public override void OnExit(MethodExecutionArgs args) {
string msg = $"[{_methodName}]: exited";
if (!String.IsNullOrWhiteSpace(_argumentsFormat)) {
msg += String.Format(". Arguments: " + _argumentsFormat, args.Arguments.ToArray());
}
Console.WriteLine(msg);
}
public override void OnException(MethodExecutionArgs args) {
string msg = $"[{_methodName}]: exception";
if (!String.IsNullOrWhiteSpace(_argumentsFormat))
{
msg += String.Format(". Arguments: " + _argumentsFormat, args.Arguments.ToArray());
}
msg += ". Details: " + args.Exception.ToString();
Console.WriteLine(msg);
}
}
What we basically do here is inheriting MethodBoundaryAspect and define what code should be executed when target method is entered, exited, and when exception is thrown. Use it like this:
public class Program {
static void Main(string[] args) {
TestStuff(1);
TestStuff(2);
TestStuff(3);
Console.ReadKey();
}
[Trace("itemId: {0}")]
static void TestStuff(int itemId) {
Console.WriteLine("Inside TestStuff: " + itemId);
if (itemId == 3)
throw new Exception("Test exception");
}
}
You can also apply that attribute to whole classes. In this case - all methods inside that class will be traced.
Ok here i have created a program that does multiple copy and adding text into files, tho its run time what i have come up with is a list_ that stores loads of keys then prints back at the end of the process instead of having loads of message boxes coming up this is what i have
the list class.
public class Messageresult : Weaons
{
private List<string> elfenliedtopfan5 = new List<string>();
public List<string> _Message
{
get { return elfenliedtopfan5; }
set { elfenliedtopfan5 = value; }
}
}
and in multiple of classes i call this like so
public void ShowMessage()
{
elfy1 = new Messageresult();
//MessageBox.Show(elfy1._Message.ToString());
update();
refreshlist();
var message = string.Join(Environment.NewLine, elfy1._Message);
MessageBox.Show(message + Environment.NewLine +
createa + Environment.NewLine + results);
elfy1._Message.Clear(); }
so this is what i use in multiple different classes and i use inheritance
tis class above is called weapons. and all my other classes inherit weapons but
the issue im having is in certain classes like my thundergun class
when i call this.
public void cliantfx()
{
elfy1 = new Messageresult();
string path = modcliant;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
File.Copy(Properties.Settings.Default.root + "//raw//clientscripts//" + ModName + ".csc", path + ModName + ".csc");
MessageBox.Show(path);
}
if (File.Exists(path + ModName + ".csc"))
{
using (StreamReader elfenliedtopfan6 = new StreamReader((path + ModName + ".csc")))
{
string elfenliedtopfan6_program = elfenliedtopfan6.ReadToEnd();
if (elfenliedtopfan6_program.Contains(#"clientscripts\_thundergun::init();"))
{
//MessageBox.Show(#"clientscripts\_thundergun::init();" + "Already Added:");
refreshlist();
elfy1._Message.Add("clientscripts\\_thundergun::init();" + "Already Added:");
}
if (!elfenliedtopfan6_program.Contains(#"clientscripts\_thundergun::init();"))
{
elfenliedtopfan6.Dispose();
if (File.Exists(path + ModName + ".csc"))
{
{
string s = Environment.NewLine
+ #" clientscripts\_thundergun::init();";
string file = path + ModName + ".csc";
List<string> lines = new List<string>(System.IO.File.ReadAllLines(file));
int index = lines.FindLastIndex(item => item.Contains(#"clientscripts\_zombiemode_tesla::init();"));
if (index != -1)
{
lines.Insert(index + 1, s);//""
}
System.IO.File.WriteAllLines(file, lines);
MessageBox.Show("Added: " + s + "To " + ModName);
}
}
and as you can see elfy1._message.Add("text here....")
is called in weapons but when it executes tho this it just gives a blank message box yet when i execute weapons_gsc it works perfectly fine
and i use the same call methord and the showmessage()
function in weapons
yet in sounds class and thundergun class it wont update it or display once its executed
so im not sure how i would go about this.
because it works perfectly fine for weapons_gsc image below show results
image of it working for weapons_gsc and weapons
the sound one you see at the end i had to make a propeties.setting.default.results
and made it = to the sound alais one only way i could get it to display the results all in one message box.
Before going further, I would like to suggest that you take a slightly different approach; i.e. I see no reason why you wouldn't simply use a logging framework like log4net and add a custom appender which would redirect messages to a text box, along with a textual log file. When your app crashes, having a log is invaluable for troubleshooting.
Synchronizing access to the logger class
Nevertheless, if you need to write these log messages from multiple threads, then you need to synchronize access to the Add method. You shouldn't expose the list as a public property, but instead create methods which will be synchronized:
public class Logger
{
private readonly object _lock = new object();
private readonly List<string> _messages = new List<string>();
public void Append(string message)
{
// locking ensures that only a single thread can enter this block
lock (_lock)
{
_messages.Add(message);
}
}
// since we are locking this method too, we can be sure that
// we will join messages into a single string and clear the list
// without being interrupted (atomically)
public string Merge()
{
lock (_lock)
{
// now you are sure you won't lose any data, because
// it's impossible for other threads to append to _messages
// between joining and clearing it
var result = string.Join(Environment.NewLine, _messages);
_messages.Clear();
return result;
}
}
}
Having something like this in place, you need to ensure that you don't create a new instance of this class on each access. This means that your class should create the "logger" only once:
public class SomeOtherClass
{
// once you add the 'readonly' keyword, compiler
// won't let you accidentally create another instance
private readonly Logger _logger = new Logger();
public void SomeMethod()
{
// _logger = new Logger(); // <-- this will not compile
_logger.Append("Some message");
}
public void SomeOtherMethod()
{
MessageBox.Show(_logger.Merge());
}
}
Making the class a singleton
Alternatively, you may want to make the logger class a singleton (in most cases not the best idea, but if this is a one time small project, it might simplify things):
public class Logger
{
#region Singleton pattern
// this is the static one-and-only logger instance, alive
// throughout the lifetime of your application
private static readonly Logger _instance = new Logger();
public static Logger Instance
{
get { return _instance; }
}
// private empty constructor is here to ensure
// that you can only access this class through the
// Logger.Instance static property
private Logger() { }
#endregion
private readonly object _lock = new object();
private readonly List<string> _messages = new List<string>();
public void Append(string message)
{
lock (_lock)
_messages.Add(message);
}
public string Merge()
{
lock (_lock)
{
var result = string.Join(Environment.NewLine, _messages);
_messages.Clear();
return result;
}
}
}
In this case, you wouldn't need to instantiate the logger class at all, and all your classes can only access a single instance, using multiple threads:
public class SomeOtherClass
{
public void SomeMethod()
{
Logger.Instance.Append("Some message");
}
public void SomeOtherMethod()
{
MessageBox.Show(Logger.Instance.Merge());
}
}
I have application for which I need to add additional hidden logging.
I have put prototype in way.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start");
new DummyTest().Report();
Console.WriteLine("End");
Console.ReadKey();
}
}
public class DummyTest
{
public void Report()
{
var reporter = new Reporter();
Console.WriteLine("Reporting");
for (var i =0; i < 155; i++)
{
reporter.Process(i);
}
Console.WriteLine("Reporting end");
}
}
public class Reporter
{
// attach behavior here
public void Process(int requestId)
{
Console.WriteLine("Processing request: {0}" , requestId);
System.Threading.Thread.Sleep(100);
}
}
Now I have new project logger.dll that contains
using System;
namespace logger
{
public class Log
{
public Log()
{
Console.WriteLine("Line executed");
}
}
}
Now I would like to execute this method every time Main gets executed. This however cannot be referenced in any other way except only by referencing the dll.
=Update=
I do not mind to have reference to that dll. But in main code I cannot have any reference to Log. I thought about using reflection in order to make this work. The problem I am trying to solve first is how to attach that to the execution.
Why I cannot call logger from main?
This is supposed to be reporting on usage of the class, monitoring usage, in order to report on performance on bottle necks.
You could do something like this:
void Main()
{
System.Console.SetOut(new CustomTextWriter());
Console.WriteLine("test");
}
public class CustomTextWriter : TextWriter
{
private TextWriter _consoleOut = null;
private Log _logger = null;
public CustomTextWriter()
{
_consoleOut = System.Console.Out;
_logger = new Log();
}
public override void Write(char[] buffer, int index, int count)
{
this.Write(new String(buffer, index, count));
}
public override void Write(string value)
{
_consoleOut.Write(value);
_logger.Write(value);
}
public override void WriteLine(string value)
{
_consoleOut.WriteLine(value);
_logger.WriteLine(value);
}
public override Encoding Encoding
{
get { return System.Text.Encoding.Default; }
}
}
Wasn't sure if you wanted to do logging without actually calling Console.WriteLine() (if yes you'll need to look at Interception) but if that's ok then this should get you through.
Hope this helps.
You could do that with reflection like this:
// load the assembly
Assembly LogDll = Assembly.LoadFile(#"Log.dll");
// get the type of the Log class
Type LogType = LogDll.GetType("logger.Log");
// get instance of the Log class
object LogInstance = Activator.CreateInstance(LogType);
// invoke class member "Log()"
LogType.InvokeMember("Log",
BindingFlags.InvokeMethod |
BindingFlags.Instance |
BindingFlags.Public,
null,
LogInstance,
null);
Although I'm not sure if the constructor "Log()" already gets called by creating the instance. You should probably move your actual log method out of the constructor. To pass arguments you can use the last parameter of InvokeMember which is an array of the type Object.
I am writing extension methods for a class, and would like to access an IDisposable object defined in a using block which will often contain calls to the extension methods.
I do not want to simply pass the IDisposable to the method calls, which would detract from the simplicity of my API's programming model. Accomplishing what I'm after would also make the code work much more like the third-party API with which I'm integrating.
I can imagine one way to go about this: register the IDisposable in some global location, perhaps tied to the current thread ID so it can be looked up in the extension methods via a factory method call or some such thing. The object could unregister itself when the using block is exited and its Dispose() method is eventually called (to make this work I imagine I might need to use a weak reference, though).
That doesn't seem very unclean, but it is a little too much roundabout for my taste. Is there some more direct way of doing this?
Here's what I'd like to do:
public static class ExtensionMethods {
public static void Foo(this Bar b) {
// Access t to enable this extension method to do its work, whatever that may be
}
}
public class Bar {
}
public class Schlemazel {
public void DoSomething() {
using (Thingamabob t = new Thingamabob()) {
Bar b = new Bar();
b.Foo();
}
}
}
EDIT:
Following is a solution implemented using weak references and a simple thread-based registration system. It seems to work and to be stable even under a fair load, but of course on a really overloaded system it could theoretically start throwing errors due to lock contention.
I thought it might be interesting for someone to see this solution, but again, it introduces needless complexity and I am only willing to do this if necessary. Again, the goal is a clean extension of a third-party API, where I can call extension methods on objects created by the third-party API, where the extension methods depend on some context that is messy to create or get for each little extension method call.
I've left in some console output statements so that if you're curious, you can actually plop these classes into a command-line project and see it all in action.
public class Context : IDisposable
{
private const int MAX_LOCK_TRIES = 3;
private static TimeSpan MAX_WRITE_LOCK_TIMEOUT = TimeSpan.FromTicks(500);
private static System.Threading.ReaderWriterLockSlim readerWriterLock = new System.Threading.ReaderWriterLockSlim();
static IDictionary<string, WeakReference<Context>> threadContexts = new Dictionary<string, WeakReference<Context>>();
private bool registered;
private string threadID;
private string ThreadID
{
get { return threadID; }
set
{
if (threadID != null)
throw new InvalidOperationException("Cannot associate this context with more than one thread");
threadID = value;
}
}
/// <summary>
/// Constructs a Context suitable for use in a using() statement
/// </summary>
/// <returns>A Context which will automatically deregister itself when it goes out of scope, i.e. at the end of a using block</returns>
public static Context CreateContext()
{
Console.WriteLine("CreateContext()");
return new Context(true);
}
private Context(bool register)
{
if (register)
{
registered = true;
try
{
RegisterContext(this);
}
catch
{
registered = false;
}
}
else
registered = false;
}
public Context()
{
registered = false;
}
public void Process(ThirdPartyObject o, params string[] arguments)
{
Console.WriteLine("Context.Process(o)");
// Process o, sometimes using the third-party API which this object has access to
// This hides away the complexity of accessing that API, including obviating the need
// to reconstruct and configure heavyweight objects to access it; calling code can
// blithely call useful methods on individual objects without knowing the messy details
}
public void Dispose()
{
if (registered)
DeregisterContext(this);
}
private static void RegisterContext(Context c)
{
if (c == null)
throw new ArgumentNullException();
c.ThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine("RegisterContext() " + c.ThreadID);
bool lockEntered = false;
int tryCount = 0;
try
{
while (!readerWriterLock.TryEnterWriteLock(TimeSpan.FromTicks(5000)))
if (++tryCount > MAX_LOCK_TRIES)
throw new OperationCanceledException("Cannot register context (timeout)");
lockEntered = true;
threadContexts[c.ThreadID] = new WeakReference<Context>(c);
}
finally
{
if (lockEntered)
readerWriterLock.ExitWriteLock();
}
}
private static void DeregisterContext(Context c)
{
if (c == null)
throw new ArgumentNullException();
else if (!c.registered)
return;
Console.WriteLine("DeregisterContext() " + c.ThreadID);
bool lockEntered = false;
int tryCount = 0;
try
{
while (!readerWriterLock.TryEnterWriteLock(TimeSpan.FromTicks(5000)))
if (++tryCount > MAX_LOCK_TRIES)
throw new OperationCanceledException("Cannot deregister context (timeout)");
lockEntered = true;
if (threadContexts.ContainsKey(c.ThreadID))
{
Context registeredContext = null;
if (threadContexts[c.ThreadID].TryGetTarget(out registeredContext))
{
if (registeredContext == c)
{
threadContexts.Remove(c.ThreadID);
}
}
else
threadContexts.Remove(c.ThreadID);
}
}
finally
{
if (lockEntered)
readerWriterLock.ExitWriteLock();
}
}
/// <summary>
/// Gets the Context for this thread, if one has been registered
/// </summary>
/// <returns>The Context for this thread, which would generally be defined in a using block using Context.CreateContext()</returns>
internal static Context GetThreadContext()
{
string threadID = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine("GetThreadContext() " + threadID);
bool lockEntered = false;
int tryCount = 0;
try
{
while (!readerWriterLock.TryEnterReadLock(TimeSpan.FromTicks(5000)))
if (++tryCount > MAX_LOCK_TRIES)
throw new OperationCanceledException("Cannot get context (timeout)");
lockEntered = true;
Context registeredContext = null;
if (threadContexts.ContainsKey(threadID))
threadContexts[threadID].TryGetTarget(out registeredContext);
return registeredContext;
}
finally
{
if (lockEntered)
readerWriterLock.ExitReadLock();
}
}
}
// Imagine this is some third-party API
public static class ThirdPartyApi
{
// Imagine this is any call to the third-party API that returns an object from that API which we'd like to decorate with an extension method
public static ThirdPartyObject GetThirdPartyObject()
{
return new ThirdPartyObject();
}
}
// Imagine this is some class from a third-party API, to which we would like to add extension methods
public class ThirdPartyObject
{
internal ThirdPartyObject() { }
}
public static class ExtensionMethods
{
public static void DoSomething(this ThirdPartyObject o) {
// get the object I need to access resources to do my work
Console.WriteLine("o.DoSomething()");
Context c = Context.GetThreadContext();
c.Process(o);
}
}
You could test it pretty simply, with some code like this:
ThirdPartyObject o;
using (Context.CreateContext())
{
o = ThirdPartyApi.GetThirdPartyObject(); // or a call to my own code to get it, encapsulating calls to the third-party API
// Call the method we've tacked on to the third party API item
o.DoSomething();
}
try
{
// If the registered context has been disposed/deregistered, this will throw an error;
// there is of course no way of knowing when it will happen, but in my simple testing
// even this first attempt always throws an error, on my relatively unburdened system.
// This means that with this model, one should not access the using-block Context
// outside of the using block, but that's of course true in general of using statements
o.DoSomething();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
System.Threading.Thread.Sleep(1000);
try
{
// Should almost certainly see an error now
o.DoSomething();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Pass the t variable to the extension method.
public static class ExtensionMethods {
public static void Foo(this Bar b, Thingamabob t) {
// Access t to enable this extension method to do its work, whatever that may be
}
}
public class Bar { }
public class Schlemazel {
public void DoSomething() {
using (Thingamabob t = new Thingamabob()) {
Bar b = new Bar();
b.Foo(t);
}
}
}