WvStreams
wvlogbuffer.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvLogBuffer is a descendant of WvLogRcv that buffers log messages for
00006  * later use.  It only keeps up to max_lines log entries for every
00007  * source/debug level, s.t. debug level <= max_level
00008  */                                                    
00009 #include "wvlogbuffer.h"
00010 #include "strutils.h"
00011 #include <time.h>
00012 
00013 WvLogBuffer::Msg::Msg(WvLog::LogLevel _level, WvStringParm _source,
00014     WvString _message) : level(_level), source(_source), message(_message)
00015 {
00016     time(&timestamp);
00017 }
00018 
00019 WvLogBuffer::Msg* WvLogBuffer::MsgCounter::add(WvLogBuffer::Msg* msg, int max)
00020 {
00021     list.append(msg, false);
00022     
00023     // Check if we need to purge anything
00024     if (list.count() > (size_t)max)
00025     {
00026         Msg* killme = list.first();
00027         list.unlink_first();
00028         return killme; 
00029     }
00030     else 
00031         return NULL;
00032 }
00033 
00034 
00035 WvLogBuffer::WvLogBuffer(int _max_lines, WvLog::LogLevel _max_level) :
00036     WvLogRcv(_max_level), counters(25)
00037 {
00038     max_lines = _max_lines;
00039 }
00040 
00041 
00042 WvLogBuffer::~WvLogBuffer()
00043 {
00044     end_line();
00045 }
00046 
00047 
00048 void WvLogBuffer::_mid_line(const char *str, size_t len)
00049 {
00050     current.put(str, len);
00051 }
00052 
00053 void WvLogBuffer::handle_msg(Msg *lastmsg)
00054 {
00055     // Stick the msg in the list of all messages
00056     msgs.append(lastmsg, true);
00057         
00058     // Check if we already have any messages of this source/level
00059     WvString type(WvString("%s:%s", last_source, last_level));
00060     MsgCounter* msgcounter = counters[type];
00061     // If not create a new tracking list for it
00062     if (!msgcounter)
00063     {
00064         msgcounter = new MsgCounter(type);
00065         counters.add(msgcounter, true);
00066     }
00067     // Now that we are sure the type exists, add the message to it
00068     Msg* killme = msgcounter->add(lastmsg, max_lines);
00069         
00070     // Delete the extra messages if we need to
00071     if (killme)
00072         msgs.unlink(killme);
00073 }
00074 
00075 void WvLogBuffer::_end_line()
00076 {
00077     if (last_level < WvLog::NUM_LOGLEVELS)
00078     {
00079         current.put('\0'); // terminating NULL
00080         Msg *lastmsg = new Msg(last_level, last_source,
00081             trim_string((char *)current.get(current.used())));
00082         
00083         handle_msg(lastmsg);
00084     }
00085     else 
00086         current.zap();
00087 }
00088 
00089 void WvLogBuffer::feed_receiver(WvLogRcv& receiver)
00090 {
00091     WvLogBuffer::MsgList::Iter i(msgs);
00092     i.rewind();
00093     while (i.next())
00094     {
00095         WvLogBuffer::Msg &msg = *i;
00096         receiver.log(msg.source, msg.level,
00097             msg.message.cstr(), msg.message.len());
00098     }
00099 }
00100 
00101 
00102 void WvLogBuffer::dump(WvStream &s)
00103 {
00104     MsgList::Iter i(messages());
00105     
00106     for (i.rewind(); i.next(); )
00107     {
00108         Msg &m = *i;
00109         s.print("%s %s<%s>: %s+\n",
00110                 m.timestamp, m.source, loglevels[m.level], m.message);
00111     }
00112 }