# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

log.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "stdmisc.h"
00027 
00028 #ifdef NL_OS_WINDOWS
00029 #include <process.h>
00030 #include <windows.h>
00031 #else
00032 #include <unistd.h>
00033 #endif
00034 
00035 #include <time.h>
00036 #include <stdarg.h>
00037 
00038 #include "nel/misc/displayer.h"
00039 #include "nel/misc/log.h"
00040 #include "nel/misc/debug.h"
00041 #include "nel/misc/path.h"
00042 
00043 using namespace std;
00044 
00045 
00046 namespace NLMISC
00047 {
00048 
00049 string *CLog::_ProcessName = NULL;
00050 
00051 CLog::CLog( TLogType logType) : _LogType (logType), _Line(-1), _FileName(NULL), _Mutex("LOG"+toString((uint)logType)), _PosSet(false)
00052 {
00053 }
00054 
00055 void CLog::setDefaultProcessName ()
00056 {
00057 #ifdef NL_OS_WINDOWS
00058         if (_ProcessName == NULL)
00059         {
00060                 _ProcessName = new string;
00061         }
00062         
00063         if ((*_ProcessName).empty())
00064         {
00065                 char name[1024];
00066                 GetModuleFileName (NULL, name, 1023);
00067                 (*_ProcessName) = CFile::getFilename(name);
00068         }
00069 #endif
00070 }
00071 
00072 void CLog::setProcessName (const std::string &processName)
00073 {
00074         if (_ProcessName == NULL)
00075         {
00076                 _ProcessName = new string;
00077         }
00078 
00079         *_ProcessName = processName;
00080 }
00081 
00082 void CLog::setPosition (sint line, char *filename)
00083 {
00084         if ( !noDisplayer() )
00085         {
00086                 _Mutex.enter();
00087                 _PosSet++;
00088             _Line = line;
00089                 _FileName = filename;
00090         }
00091 }
00092 
00094 void CLog::unsetPosition()
00095 {
00096         nlassert( !noDisplayer() );
00097 
00098         if ( _PosSet > 0 )
00099         {
00100                 _FileName = NULL;
00101                 _Line = -1;
00102                 _PosSet--;
00103                 _Mutex.leave(); // needs setPosition() to have been called
00104         }
00105 }
00106 
00107 
00108 void CLog::addDisplayer (IDisplayer *displayer, bool bypassFilter)
00109 {
00110         if (displayer == NULL)
00111         {
00112                 nlwarning ("Trying to add a NULL displayer");
00113                 return;
00114         }
00115 
00116         if (bypassFilter)
00117         {
00118                 CDisplayers::iterator idi = std::find (_BypassFilterDisplayers.begin (), _BypassFilterDisplayers.end (), displayer);
00119                 if (idi == _BypassFilterDisplayers.end ())
00120                 {
00121                         _BypassFilterDisplayers.push_back (displayer);
00122                 }
00123                 else
00124                 {
00125                         nlwarning ("Couldn't add the displayer, it was already added");
00126                 }
00127         }
00128         else
00129         {
00130                 CDisplayers::iterator idi = std::find (_Displayers.begin (), _Displayers.end (), displayer);
00131                 if (idi == _Displayers.end ())
00132                 {
00133                         _Displayers.push_back (displayer);
00134                 }
00135                 else
00136                 {
00137                         nlwarning ("Couldn't add the displayer, it was already added");
00138                 }
00139         }
00140 }
00141 
00142 void CLog::removeDisplayer (IDisplayer *displayer)
00143 {
00144         if (displayer == NULL)
00145         {
00146                 nlwarning ("Trying to remove a NULL displayer");
00147                 return;
00148         }
00149 
00150         CDisplayers::iterator idi = std::find (_Displayers.begin (), _Displayers.end (), displayer);
00151         if (idi != _Displayers.end ())
00152         {
00153                 _Displayers.erase (idi);
00154         }
00155 
00156         idi = std::find (_BypassFilterDisplayers.begin (), _BypassFilterDisplayers.end (), displayer);
00157         if (idi != _BypassFilterDisplayers.end ())
00158         {
00159                 _BypassFilterDisplayers.erase (idi);
00160         }
00161 
00162 }
00163 
00164 void CLog::removeDisplayer (const char *displayerName)
00165 {
00166         if (displayerName == NULL || displayerName[0] == '\0')
00167         {
00168                 nlwarning ("Trying to remove an empty displayer name");
00169                 return;
00170         }
00171 
00172         CDisplayers::iterator idi;
00173         for (idi = _Displayers.begin (); idi != _Displayers.end ();)
00174         {
00175                 if ((*idi)->DisplayerName == displayerName)
00176                 {
00177                         idi = _Displayers.erase (idi);
00178                 }
00179                 else
00180                 {
00181                         idi++;
00182                 }
00183         }
00184 
00185         for (idi = _BypassFilterDisplayers.begin (); idi != _BypassFilterDisplayers.end ();)
00186         {
00187                 if ((*idi)->DisplayerName == displayerName)
00188                 {
00189                         idi = _BypassFilterDisplayers.erase (idi);
00190                 }
00191                 else
00192                 {
00193                         idi++;
00194                 }
00195         }
00196 }
00197 
00198 IDisplayer *CLog::getDisplayer (const char *displayerName)
00199 {
00200         if (displayerName == NULL || displayerName[0] == '\0')
00201         {
00202                 nlwarning ("Trying to get an empty displayer name");
00203                 return NULL;
00204         }
00205 
00206         CDisplayers::iterator idi;
00207         for (idi = _Displayers.begin (); idi != _Displayers.end (); idi++)
00208         {
00209                 if ((*idi)->DisplayerName == displayerName)
00210                 {
00211                         return *idi;
00212                 }
00213         }
00214         for (idi = _BypassFilterDisplayers.begin (); idi != _BypassFilterDisplayers.end (); idi++)
00215         {
00216                 if ((*idi)->DisplayerName == displayerName)
00217                 {
00218                         return *idi;
00219                 }
00220         }
00221         return NULL;
00222 }
00223 
00224 /*
00225  * Returns true if the specified displayer is attached to the log object
00226  */
00227 bool CLog::attached(IDisplayer *displayer) const 
00228 {
00229         return (find( _Displayers.begin(), _Displayers.end(), displayer ) != _Displayers.end()) ||
00230                         (find( _BypassFilterDisplayers.begin(), _BypassFilterDisplayers.end(), displayer ) != _BypassFilterDisplayers.end());
00231 }
00232 
00233 static string TempString;
00234 static TDisplayInfo TempArgs;
00235 
00236 
00237 void CLog::displayString (const char *str)
00238 {
00239         const char *disp = NULL;
00240         TDisplayInfo localargs, *args = NULL;
00241 
00242         setDefaultProcessName ();
00243 
00244         if(strchr(str,'\n') == NULL)
00245         {
00246                 if (TempString.empty())
00247                 {
00248                         time (&TempArgs.Date);
00249                         TempArgs.LogType = _LogType;
00250                         TempArgs.ProcessName = *_ProcessName;
00251                         TempArgs.ThreadId = getThreadId();
00252                         TempArgs.Filename = _FileName;
00253                         TempArgs.Line = _Line;
00254                         TempArgs.CallstackAndLog = "";
00255 
00256                         TempString = str;
00257                 }
00258                 else
00259                 {
00260                         TempString += str;
00261                 }
00262                 return;
00263         }
00264         else
00265         {
00266                 if (TempString.empty())
00267                 {
00268                         time (&localargs.Date);
00269                         localargs.LogType = _LogType;
00270                         localargs.ProcessName = *_ProcessName;
00271                         localargs.ThreadId = getThreadId();
00272                         localargs.Filename = _FileName;
00273                         localargs.Line = _Line;
00274                         localargs.CallstackAndLog = "";
00275 
00276                         disp = str;
00277                         args = &localargs;
00278                 }
00279                 else
00280                 {
00281                         TempString += str;
00282                         disp = TempString.c_str();
00283                         args = &TempArgs;
00284                 }
00285         }
00286 
00287         // send to all bypass filter displayers
00288         for (CDisplayers::iterator idi=_BypassFilterDisplayers.begin(); idi!=_BypassFilterDisplayers.end(); idi++ )
00289         {
00290                 (*idi)->display( *args, disp );
00291         }
00292 
00293         // get the log at the last minute to be sure to have everything
00294         if(args->LogType == LOG_ERROR || args->LogType == LOG_ASSERT)
00295         {
00296                 getCallStackAndLog (args->CallstackAndLog, 4);
00297         }
00298 
00299         if (passFilter (disp))
00300         {
00301                 // Send to the attached displayers
00302                 for (CDisplayers::iterator idi=_Displayers.begin(); idi!=_Displayers.end(); idi++ )
00303                 {
00304                         (*idi)->display( *args, disp );
00305                 }
00306         }
00307         TempString = "";
00308         unsetPosition();
00309 }
00310 
00311 
00312 /*
00313  * Display the string with decoration and final new line to all attached displayers
00314  */
00315 void CLog::displayNL (const char *format, ...)
00316 {
00317         if ( noDisplayer() )
00318         {
00319                 return;
00320         }
00321 
00322         char *str;
00323         NLMISC_CONVERT_VARGS (str, format, 256/*NLMISC::MaxCStringSize*/);
00324 
00325         if (strlen(str)<256/*NLMISC::MaxCStringSize*/-1)
00326                 strcat (str, "\n");
00327         else
00328                 str[256/*NLMISC::MaxCStringSize*/-2] = '\n';
00329 
00330         displayString (str);
00331 }
00332  
00333 /*
00334  * Display the string with decoration to all attached displayers
00335  */
00336 void CLog::display (const char *format, ...)
00337 {
00338         if ( noDisplayer() )
00339         {
00340                 return;
00341         }
00342 
00343         char *str;
00344         NLMISC_CONVERT_VARGS (str, format, 256/*NLMISC::MaxCStringSize*/);
00345 
00346         displayString (str);
00347 }
00348 
00349 
00350 void CLog::displayRawString (const char *str)
00351 {
00352         const char *disp = NULL;
00353         TDisplayInfo localargs, *args = NULL;
00354 
00355         setDefaultProcessName ();
00356 
00357         if(strchr(str,'\n') == NULL)
00358         {
00359                 if (TempString.empty())
00360                 {
00361                         localargs.Date = 0;
00362                         localargs.LogType = CLog::LOG_NO;
00363                         localargs.ProcessName = "";
00364                         localargs.ThreadId = 0;
00365                         localargs.Filename = NULL;
00366                         localargs.Line = -1;
00367                         localargs.CallstackAndLog = "";
00368 
00369                         TempString = str;
00370                 }
00371                 else
00372                 {
00373                         TempString += str;
00374                 }
00375                 return;
00376         }
00377         else
00378         {
00379                 if (TempString.empty())
00380                 {
00381                         localargs.Date = 0;
00382                         localargs.LogType = CLog::LOG_NO;
00383                         localargs.ProcessName = "";
00384                         localargs.ThreadId = 0;
00385                         localargs.Filename = NULL;
00386                         localargs.Line = -1;
00387                         localargs.CallstackAndLog = "";
00388 
00389                         disp = str;
00390                         args = &localargs;
00391                 }
00392                 else
00393                 {
00394                         TempString += str;
00395                         disp = TempString.c_str();
00396                         args = &TempArgs;
00397                 }
00398         }
00399 
00400         // send to all bypass filter displayers
00401         for (CDisplayers::iterator idi=_BypassFilterDisplayers.begin(); idi!=_BypassFilterDisplayers.end(); idi++ )
00402         {
00403                 (*idi)->display( *args, disp );
00404         }
00405 
00406         // get the log at the last minute to be sure to have everything
00407         if(args->LogType == LOG_ERROR || args->LogType == LOG_ASSERT)
00408         {
00409                 getCallStackAndLog (args->CallstackAndLog, 4);
00410         }
00411 
00412         if ( passFilter( disp ) )
00413         {
00414                 // Send to the attached displayers
00415                 for ( CDisplayers::iterator idi=_Displayers.begin(); idi!=_Displayers.end(); idi++ )
00416                 {
00417                         (*idi)->display( *args, disp );
00418                 }
00419         }
00420         TempString = "";
00421         unsetPosition();
00422 }
00423 
00424 /*
00425  * Display a string (and nothing more) to all attached displayers
00426  */
00427 void CLog::displayRawNL( const char *format, ... )
00428 {
00429         if ( noDisplayer() )
00430         {
00431                 return;
00432         }
00433 
00434         char *str;
00435         NLMISC_CONVERT_VARGS (str, format, 256/*NLMISC::MaxCStringSize*/);
00436 
00437         if (strlen(str)<256/*NLMISC::MaxCStringSize*/-1)
00438                 strcat (str, "\n");
00439         else
00440                 str[256/*NLMISC::MaxCStringSize*/-2] = '\n';
00441 
00442         displayRawString(str);
00443 }
00444 
00445 /*
00446  * Display a string (and nothing more) to all attached displayers
00447  */
00448 void CLog::displayRaw( const char *format, ... )
00449 {
00450         if ( noDisplayer() )
00451         {
00452                 return;
00453         }
00454 
00455         char *str;
00456         NLMISC_CONVERT_VARGS (str, format, 256/*NLMISC::MaxCStringSize*/);
00457 
00458         displayRawString(str);
00459 }
00460 
00461 
00462 void CLog::forceDisplayRaw (const char *format, ...)
00463 {
00464         if ( noDisplayer() )
00465         {
00466                 return;
00467         }
00468 
00469         char *str;
00470         NLMISC_CONVERT_VARGS (str, format, 256/*NLMISC::MaxCStringSize*/);
00471 
00472         TDisplayInfo args;
00473 
00474         // Send to the attached displayers
00475         for ( CDisplayers::iterator idi=_Displayers.begin(); idi!=_Displayers.end(); idi++ )
00476         {
00477                 (*idi)->display( args, str );
00478         }
00479 }
00480 
00481 
00482 
00483 /*
00484  * Returns true if the string must be logged, according to the current filter
00485  */
00486 bool CLog::passFilter( const char *filter )
00487 {
00488         bool yes = _PositiveFilter.empty();
00489 
00490         bool found;
00491         list<string>::iterator ilf;
00492 
00493         // 1. Positive filter
00494         for ( ilf=_PositiveFilter.begin(); ilf!=_PositiveFilter.end(); ++ilf )
00495         {
00496                 found = ( strstr( filter, (*ilf).c_str() ) != NULL );
00497                 if ( found )
00498                 {
00499                         yes = true; // positive filter passed (no need to check another one)
00500                         break;
00501                 }
00502                 // else try the next one
00503         }
00504         if ( ! yes )
00505         {
00506                 return false; // positive filter not passed
00507         }
00508 
00509         // 2. Negative filter
00510         for ( ilf=_NegativeFilter.begin(); ilf!=_NegativeFilter.end(); ++ilf )
00511         {
00512                 found = ( strstr( filter, (*ilf).c_str() ) != NULL );
00513                 if ( found )
00514                 {
00515                         return false; // negative filter not passed (no need to check another one)
00516                 }
00517         }
00518         return true; // negative filter passed
00519 }
00520 
00521 
00522 /*
00523  * Removes a filter by name. Returns true if it was found.
00524  */
00525 void CLog::removeFilter( const char *filterstr )
00526 {
00527         if (filterstr == NULL)
00528         {
00529                 _PositiveFilter.clear();
00530                 _NegativeFilter.clear();
00531                 //displayNL ("CLog::addNegativeFilter('%s')", filterstr);
00532         }
00533         else
00534         {
00535                 _PositiveFilter.remove( filterstr );
00536                 _NegativeFilter.remove( filterstr );
00537                 //displayNL ("CLog::removeFilter('%s')", filterstr);
00538         }
00539 }
00540 
00541 void CLog::displayFilter( CLog &log )
00542 {
00543         std::list<std::string>::iterator it;
00544         log.displayNL ("Positive Filter(s):");
00545         for (it = _PositiveFilter.begin (); it != _PositiveFilter.end (); it++)
00546         {
00547                 log.displayNL ("'%s'", (*it).c_str());
00548         }
00549         log.displayNL ("Negative Filter(s):");
00550         for (it = _NegativeFilter.begin (); it != _NegativeFilter.end (); it++)
00551         {
00552                 log.displayNL ("'%s'", (*it).c_str());
00553         }
00554 }
00555 
00556 void CLog::addPositiveFilter( const char *filterstr )
00557 {
00558         //displayNL ("CLog::addPositiveFilter('%s')", filterstr);
00559         _PositiveFilter.push_back( filterstr );
00560 }
00561 
00562 void CLog::addNegativeFilter( const char *filterstr )
00563 {
00564         //displayNL ("CLog::addNegativeFilter('%s')", filterstr);
00565         _NegativeFilter.push_back( filterstr );
00566 }
00567 
00568 void CLog::resetFilters()
00569 {
00570         //displayNL ("CLog::resetFilter()");
00571         _PositiveFilter.clear();
00572         _NegativeFilter.clear();
00573 }
00574 
00575 } // NLMISC
00576