tags:

views:

137

answers:

5

Hi,

I'm trying to implement a log viewer in my application. The idea is simple, a listbox that shows some messages sended from other classes, but I don't know what is the best way to do this.

My initial thought was to make a Logger class (singletone) that contains a List or Queue, then I'll add a method AddMessage(string s) or something like that. When this method is called it will add the message to the list or queue and it will fire a NewMessage event. This event is because I don't think that is a good idea to check the list every some amount of time. The sequence of messages could be 3 consecutives, then 40 minutes without nothing, then a few more ...

So, in my form class (or wherever I want to receive the messages) I will listen to this event to empty the list or queue (this is because I should be able to send messages even when the listbox (final receptor) has not been created). The idea of the list is to save messages when no one is listening the event.

Also, i've put a restriction of 300 messages... so the oldest ones will be deleted everytime i'm going to add new ones... something like this:

while(listbox.Items.Count > 300)
{
    listbox.Items.RemoveAt(0);
}

Do you think that this is the best approach?

Thanks for your time. Best regards.

Edit 1: I don't want to use another framework.

Edit 2: STOP suggesting frameworks or another application. I want to learn the logic behind, and if what i was proposing is right or wrong!

+3  A: 

Any reason not to use existing technologies?

  • Log4Net or some other framework to write out to a log file
  • A text editor (and text filters, grep etc) to view and filter the log files

EDIT: I would still be tempted to use Log4Net and have a listener for some categories/levels which dumps to a scrolling textbox. That way you can also log (with possibly more detail) to a file.

EDIT: If you want to learn, then I would suggest looking at the design and implementation of Log4Net. Work out its strengths and weaknesses with respect to your particular situation.

Jon Skeet
I think I didn't express well. I don't want to write a log file, I want to add a logger to my application ... like the one in ImgBurn or uTorrent, a place where to show to the user, what the application is doing. Sorry, but my english is not good.
Matías
Also, I don't want to use another framework.
Matías
Then you'll be reinventing the wheel. Why not take advantage of what other people have already designed, written and debugged?
Jon Skeet
Because I want to learn. I just wanted to know if the logic of what i'm suggesting is alright or not.
Matías
Jon, do you happen to know how `tail -f` is implemented, i.e. how to read the new lines from the end of a text file which someone else is appending to?
ChrisW
@Chris - I don't know, but the beauty of open source is that you can look for yourself.
Jon Skeet
(I suspect that just opening for shared reading will be fine though.)
Jon Skeet
Sharing's not a problem, it's the synchronization that I don't know about: is the reader polling, or has it blocked on something until more data has been written? Anyway you're right: I could look. This was just idle curiosity.
ChrisW
+1  A: 

I think I'm with @Jon Skeet on this one. Use an existing log facility and couple that with some sort of log reader in your application. If you use log4net, you can log to a database and have your log view simply poll the database periodically for new messages. If you log to a file, you can use a FileSystemWatcher to detect changes in the log file and reload your view. It would be less work and you could have confidence that the solution is more robust by relying on an existing, well-regarded solution and extending it.

tvanfosson
+1  A: 

I would create a class that would be defined in the main() of the program. The class would contain a linked list that would allow for scalability for the logs. Then whenever a function needed to log something it could call a operator of the class to log something. You would need to be careful in terms of mutex's if you are going to be using threads.

EDIT:

The idea would be that you declare a class that contains all the logs globally. So you create a class that contains all the logs and the ability to display them. You would define a variable of that class type and define other classes to be able to use that global class variable to log.

Suroot
could you provide a simple example of what are you suggesting? I don't see why should it be in the main() of the program. I need to "log" or send messages from other classes too.
Matías
also, this is the type of discussion that i was looking for ...
Matías
+3  A: 

Some of the questions to consider are:

  • Is your application multi-threaded? Is the thread[s] which write[s] the messages the same as the UI thread which reads the messages and populates the list box?

  • How many messages per second and being created?

  • How many times per second do you want to update the list box?

  • What's the maximum number of messages over time? Do you display them all in the list box, or do you discard older ones?

  • Do you want log the messages into a file as well (e.g. for tech support purposes)?

  • Is the listbox (the UI element) the only place where messages are stored? Is the listbox always displayed, or can the user hide/destroy it?

  • How sophisticated are the end-users? Can you ask them to use other (better) tools to view your log file, or do you need to implement a (relatively unsophisticated) viewer into your own UI?

Sorry to answer your question with questions, but these are questions which need answering before you can say "is this the best approach?".


it's not a multithreaded application, is a freaking small application that I don't want to overload.

If the application isn't multi-threaded, then the 'simplest thing that could possibly work' would be to not bother with a list or queue; and instead, let your other classes append messages directly into the UI listbox element (perhaps via a delegate), for example:

class MyClass
{
  Action<string> log;
  MyClass(Action<string> log)
  {
    this.log = log;
  }
  void Something()
  {
    //log a message
    log("Hello world!");
  }
}
class MyForm
{
  ListBox listBox = new ListBox();
  MyClass myClass;
  MyForm()
  {
    //create a delegate which logs strings
    //by writing them to the ListBox
    Action<string> log = delegate(string s) {
      listBox.Items.Add(s);
    };
    //pass this logger to classes which need to use it
    myClass = new MyClass(log);
    //test it
    myClass.Something();
  }
}


Here's similar code using a non-anonymous delegate, with some extra functionality as requested in one of your comments:

class MyForm
{
  ListBox listBox = new ListBox();
  MyClass myClass;
  MyForm()
  {
    //pass the Log action to classes which need to use it
    myClass = new MyClass(Log);
    //test it
    myClass.Something();
  }

  ///logs strings by writing them to the ListBox
  void Log(string s)
  {
    if (listBox.Items.Count == 300)
      listBox.Items.RemoveAt(0);
    listBox.Items.Add(s);
  }
}


I think I answer wrong the (6). I should be able to send messages even if the listbox has not been created yet... that's why I suggested a List or Queue

In this case, you do need storage other than only the ListBox. Your suggestion would work. An alternative suggestion is:

  • When you create your ListBox, populate it from the List (using the ListBox.Items.AddRange method)
  • In the Log function, if the ListBox doesn't exist then write the message to the List, else if the ListBox does exist then write the message to the ListBox.

Doing this might be (very slightly) simpler than defining, listening to, and firing an event.

ChrisW
(1) Is not multitheaded(2) Could be 5 messages in a lapse of a second, then 40 minutes without messages, then 1 ... but they are not that frequent(3) I was thinking to update the listbox only when I receive a message(4) 300, if listbox.items>300 i discard the oldest(5) no
Matías
(6) yes, it's the only place and cannot be hide (7) They only need to view the listbox if the want to know what the application is doing, nothing more, nothing less.
Matías
Thanks!, mmm.. that seems like a better option of what i was suggesting, but I think I answer wrong the (6). I should be able to send messages even if the listbox has not been created yet... that's why I suggested a List<string> or Queue<string>
Matías
Your last suggestion is really good! Many thanks for your help
Matías
+1  A: 

"Because I want to learn. I just wanted to know if the logic of what i'm suggesting is alright or not."

Your strategy as originally outlined should work. Rather than continuing this debate, I suggest that you go ahead with your design. You'll probably make changes along the way but it will be a learning experience, and in the end, you'll have something that will work well for your purposes.

jdigital