00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include <stdlib.h>
00044 #include <stdio.h>
00045
00046 #include "OSGConfig.h"
00047
00048 #include <string>
00049 #include <iostream>
00050
00051 #include <stdio.h>
00052 #include <stdarg.h>
00053
00054 #include "OSGLog.h"
00055 #include "OSGBaseFunctions.h"
00056
00057 OSG_USING_NAMESPACE
00058
00059 #ifndef OSG_DEFAULT_LOG_LEVEL
00060 # define OSG_DEFAULT_LOG_LEVEL LOG_WARNING
00061 #endif
00062
00063 #ifndef OSG_DEFAULT_LOG_TYPE
00064 # define OSG_DEFAULT_LOG_TYPE LOG_STDERR
00065 #endif
00066
00067
00068
00069
00070
00071
00072 LogBuf::LogBuf(UInt32 bufferSize) :
00073 std::streambuf( ),
00074 _enabled (true),
00075 _chunkBag ( ),
00076 _callback (NULL),
00077 _clientData (NULL)
00078 {
00079 setg(0, 0, 0);
00080
00081 if(bufferSize > 0)
00082 {
00083 Char8 *buffer = new Char8[bufferSize];
00084
00085 setp(buffer, buffer + bufferSize - 1);
00086 }
00087 else
00088 {
00089 setp(0, 0);
00090 }
00091 }
00092
00093 LogBuf::~LogBuf(void)
00094 {
00095 delete [] pbase();
00096
00097 _callback = NULL;
00098 }
00099
00103 void LogBuf::clearChunkBag(void)
00104 {
00105 std::list<LogBuf::Chunk*>::iterator cI;
00106
00107 for(cI = _chunkBag.begin(); cI != _chunkBag.end(); ++cI)
00108 delete *cI;
00109
00110 _chunkBag.clear();
00111 }
00112
00113
00114 void LogBuf::setCallback ( LogBuf::Callback cb, void *clientData,
00115 bool flushData )
00116 {
00117 std::list<LogBuf::Chunk*>::iterator cI;
00118 LogBuf::Chunk *chunk;
00119
00120 if(cb)
00121 {
00122 if(flushData)
00123 {
00124 for(cI = _chunkBag.begin(); cI != _chunkBag.end(); cI++)
00125 {
00126 if((chunk = *cI))
00127 cb(chunk->data,chunk->size,clientData);
00128 }
00129 }
00130
00131 _callback = cb;
00132 _clientData = clientData;
00133 }
00134 }
00135
00136
00137 void LogBuf::removeCallback(void)
00138 {
00139 _callback = 0;
00140 }
00141
00142
00143 void LogBuf::write(const Char8 *buffer, std::streamsize size)
00144 {
00145 Chunk *chunk = 0;
00146 Callback cb = NULL;
00147
00148 if(_enabled)
00149 {
00150 chunk = new Chunk;
00151
00152 chunk->size = size;
00153 chunk->data = new Char8[size];
00154
00155 memcpy(chunk->data, buffer, size);
00156
00157 _chunkBag.push_back(chunk);
00158 }
00159
00160 if ((cb = _callback))
00161 cb(buffer,size, _clientData);
00162 }
00163
00164 int LogBuf::overflow(Int32 c)
00165 {
00166 if(!pptr())
00167 return EOF;
00168
00169 if(c != EOF)
00170 {
00171
00172 *pptr() = c;
00173
00174 pbump(1);
00175
00176
00177 std::streamsize size = pptr() - pbase();
00178
00179 if(size > 0)
00180 {
00181 write(pbase(), size);
00182 pbump(-size);
00183 }
00184 }
00185
00186 return 0;
00187 }
00188
00189 int LogBuf::sync(void)
00190 {
00191 if(!pptr())
00192 return EOF;
00193
00194
00195 std::streamsize size = pptr() - pbase();
00196
00197 if(size > 0)
00198 {
00199 write(pbase(), size);
00200 pbump(-size);
00201 }
00202
00203 return 0;
00204 }
00205
00206 std::streamsize LogBuf::xsputn(const Char8 *buffer, std::streamsize size)
00207 {
00208 if(size > 0)
00209 {
00210 if(!pptr())
00211 return 0;
00212
00213 std::streamsize s = epptr() - pptr();
00214
00215 if(s >= size)
00216 {
00217
00218 memcpy(pptr(), buffer, size);
00219 pbump(size);
00220 }
00221 else
00222 {
00223
00224 s = pptr() - pbase();
00225
00226 if (s > 0)
00227 {
00228 write(pbase(), s);
00229 pbump(-s);
00230 }
00231
00232
00233 write(buffer, size);
00234 }
00235 }
00236
00237 return size;
00238 }
00239
00240
00241
00242
00243
00247 Log::nilbuf *Log::_nilbufP = NULL;
00248 std::ostream *Log::_nilstreamP = NULL;
00249
00250 const Char8 *Log::_levelName[] =
00251 {
00252 "LOG",
00253 "FATAL",
00254 "WARNING",
00255 "NOTICE",
00256 "INFO",
00257 "DEBUG",
00258 0
00259 };
00260
00261 const Char8 *Log::_levelColor[] =
00262 {
00263 0,
00264 "\x1b[31m",
00265 "\x1b[33m",
00266 0,
00267 0,
00268 0,
00269 0
00270 };
00271
00272
00275 bool Log::colorHeader(LogLevel level, const char *sep)
00276 {
00277 #if defined (OSG_WIN_TYPES) && !defined(OSG_NO_WINDOWD_H_INCLUDE)
00278 bool ok = true;
00279 std::string str("");
00280 LPSTR colStr;
00281 DWORD cWritten;
00282 WORD oldColAttrs, colAttrs;
00283 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
00284 HANDLE hOutput = INVALID_HANDLE_VALUE;
00285
00286 switch (_logType)
00287 {
00288 case LOG_STDERR:
00289 hOutput = GetStdHandle(STD_ERROR_HANDLE);
00290 break;
00291 case LOG_STDOUT:
00292 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
00293 break;
00294 default:
00295 break;
00296 }
00297
00298 if ( hOutput == INVALID_HANDLE_VALUE ||
00299 !GetConsoleScreenBufferInfo(hOutput, &csbiInfo) )
00300 {
00301 ok = false;
00302 }
00303 else
00304 {
00305 oldColAttrs = csbiInfo.wAttributes;
00306
00307 switch (level)
00308 {
00309 case LOG_FATAL:
00310 colAttrs = FOREGROUND_RED | FOREGROUND_INTENSITY;
00311 break;
00312 case LOG_WARNING:
00313 colAttrs = FOREGROUND_RED | FOREGROUND_GREEN;
00314 break;
00315 default:
00316 colAttrs = oldColAttrs;
00317 break;
00318 }
00319
00320 if(_levelName[level] != NULL)
00321 str = _levelName[level];
00322 if(sep != NULL)
00323 str += sep;
00324
00325 colStr = (LPSTR)str.c_str();
00326
00327 if ( !SetConsoleTextAttribute(hOutput, colAttrs) ||
00328 !WriteFile(hOutput, colStr, lstrlen(colStr), &cWritten, NULL) ||
00329 !SetConsoleTextAttribute(hOutput, oldColAttrs) )
00330 {
00331 ok = false;
00332 }
00333 }
00334
00335 return ok;
00336 #endif
00337
00338 return false;
00339 }
00340
00341
00342 Log::Log(LogType logType, LogLevel logLevel) :
00343 std::ostream (_nilbufP == NULL ?
00344 _nilbufP = new Log::nilbuf() : _nilbufP),
00345 _logType (logType ),
00346 _logLevel (logLevel ),
00347 _fileStream ( ),
00348 _logBuf ( ),
00349 _headerElem ( 0),
00350 _moduleHandling(LOG_MODULE_ALL)
00351 {
00352 if(_nilstreamP == NULL)
00353 _nilstreamP = new std::ostream(_nilbufP);
00354
00355 for(UInt32 i = 0; i < sizeof(_streamVec)/sizeof(LogOStream *); i++)
00356 {
00357 #ifdef OSG_HAS_NILBUF
00358 _streamVec[i] = new LogOStream(_nilbufP);
00359 #else
00360 _streamVec[i] = new LogOStream(_nilStreamP->rdbuf());
00361 #endif
00362 }
00363
00364 setHeaderElem(LOG_TYPE_HEADER);
00365
00366 _refTime = getSystemTime();
00367
00368 setLogLevel(logLevel);
00369 }
00370
00374 Log::Log(const Char8 *fileName, LogLevel logLevel) :
00375 std::ostream (_nilbufP == NULL ?
00376 _nilbufP = new Log::nilbuf() : _nilbufP),
00377 _logType (LOG_FILE ),
00378 _logLevel (logLevel ),
00379 _fileStream ( ),
00380 _logBuf ( ),
00381 _headerElem ( 0),
00382 _moduleHandling(LOG_MODULE_ALL)
00383 {
00384 if(_nilstreamP == NULL)
00385 _nilstreamP = new std::ostream(_nilbufP);
00386
00387 for(UInt32 i = 0; i < sizeof(_streamVec)/sizeof(LogOStream *); i++)
00388 {
00389 #ifdef OSG_HAS_NILBUF
00390 _streamVec[i] = new LogOStream(_nilbufP);
00391 #else
00392 _streamVec[i] = new LogOStream(_nilStreamP->rdbuf());
00393 #endif
00394 }
00395
00396 _refTime = getSystemTime();
00397
00398 setHeaderElem(LOG_TYPE_HEADER);
00399 setLogFile (fileName);
00400 setLogLevel (logLevel);
00401 }
00402
00403 Log::~Log(void)
00404 {
00405 setLogFile(NULL, true);
00406 }
00407
00408
00409
00413 void Log::setHeaderElem(UInt32 elemMask, bool force)
00414 {
00415 Char8 *env;
00416
00417 if(!force && (this == osgLogP) && (env = getenv( "OSG_LOG_HEADER" )))
00418 {
00419 osgLog() << "Log::setHeaderElem: overriden by envvar OSG_LOG_HEADER '"
00420 << env << "'." << endLog;
00421
00422 elemMask = LogHeaderElem(atoi(env));
00423 }
00424
00425 _headerElem = elemMask;
00426 }
00427
00431 void Log::addHeaderElem(LogHeaderElem elem, bool force)
00432 {
00433 setHeaderElem((_headerElem | elem), force);
00434 }
00435
00439 void Log::delHeaderElem(LogHeaderElem elem, bool force)
00440 {
00441 setHeaderElem((_headerElem & ~elem),force);
00442 }
00443
00447 bool Log::hasHeaderElem(LogHeaderElem elem)
00448 {
00449 return (_headerElem & elem) != 0;
00450 }
00451
00452 void Log::addModuleHandling(LogModuleHandling handling,
00453 bool OSG_CHECK_ARG(force))
00454 {
00455 _moduleHandling |= handling;
00456 }
00457
00458 void Log::delModuleHandling(LogModuleHandling handling,
00459 bool OSG_CHECK_ARG(force))
00460 {
00461 _moduleHandling &= ~handling;
00462 }
00463
00464 void Log::addModuleName(const Char8 *module, bool isStatic)
00465 {
00466 Module m;
00467 int len;
00468
00469 if(module && *module)
00470 {
00471 _moduleList.push_back(m);
00472
00473 if(isStatic)
00474 {
00475 _moduleList.back().name = module;
00476 _moduleList.back().isStatic = true;
00477 }
00478 else
00479 {
00480 len = strlen(module);
00481
00482 _moduleList.back().name = new Char8[len + 1];
00483
00484 strcpy(const_cast<Char8 *>(_moduleList.back().name), module);
00485
00486 _moduleList.back().isStatic = false;
00487 }
00488 }
00489 }
00490
00491 void Log::delModuleName(const Char8 *OSG_CHECK_ARG(module))
00492 {
00493 }
00494
00495 bool Log::hasModule(const Char8 *module)
00496 {
00497 bool retCode = false;
00498 std::list<Module>::iterator mI;
00499
00500 if(module && *module)
00501 {
00502 for( mI = _moduleList.begin();
00503 retCode || (mI != _moduleList.end());
00504 ++mI)
00505 {
00506 retCode = (mI->isStatic) ?
00507 (module == mI->name) : (!strcmp(module,mI->name));
00508 }
00509 }
00510
00511 return retCode;
00512 }
00513
00514 bool Log::checkModule(const Char8 *module)
00515 {
00516 bool retCode = false;
00517 std::list<Module>::iterator mI;
00518
00519 if(_moduleHandling != LOG_MODULE_NONE)
00520 {
00521 if(_moduleHandling == LOG_MODULE_ALL)
00522 {
00523 retCode = true;
00524 }
00525 else
00526 {
00527 if(module && &module)
00528 {
00529 if(hasModule(module))
00530 {
00531 if(_moduleHandling & LOG_MODULE_KNOWN)
00532 retCode = true;
00533 }
00534 else
00535 {
00536 if(_moduleHandling & LOG_MODULE_UNKNOWN)
00537 retCode = true;
00538 }
00539 }
00540 else
00541 {
00542 if(_moduleHandling & LOG_MODULE_UNDEFINED)
00543 retCode = true;
00544 }
00545 }
00546 }
00547
00548 return retCode;
00549 }
00550
00551
00552 LogType Log::getLogType(void)
00553 {
00554 return _logType;
00555 }
00556
00561 void Log::setLogType(LogType logType, bool force)
00562 {
00563 static Char8 *typenames[] =
00564 {
00565 "none",
00566 "-",
00567 "stdout",
00568 "stderr",
00569 "file",
00570 "buffer",
00571 NULL
00572 };
00573
00574 static LogType types [] =
00575 {
00576 LOG_NONE,
00577 LOG_STDOUT,
00578 LOG_STDOUT,
00579 LOG_STDERR,
00580 LOG_FILE,
00581 LOG_BUFFER
00582 };
00583
00584 static Int32 typeCount = sizeof(types) / sizeof(LogType);
00585
00586 Char8 *et;
00587 Int32 lt;
00588 Int32 i;
00589
00590 if(!force && (this == osgLogP) && (et = getenv("OSG_LOG_TYPE")))
00591 {
00592 osgLog() << "Log::setLogType: overriden by envvar OSG_LOG_TYPE '"
00593 << et << "'." << std::endl;
00594
00595 if(sscanf(et, "%d", <) != 1)
00596 {
00597 for(i = 0; typenames[i]; i++)
00598 {
00599 if(!stringcasecmp(et, typenames[i]))
00600 {
00601 _logType = types[i];
00602 break;
00603 }
00604 }
00605
00606 if(! typenames[i])
00607 {
00608 _logType = LOG_STDERR;
00609
00610 osgLog() << "Log::setLogType: couldn't interpret envvar, "
00611 << "set to LOG_STDERR!"
00612 << std::endl;
00613 }
00614 }
00615 else
00616 {
00617 if(lt < 0)
00618 {
00619 lt = 0;
00620 }
00621 else
00622 {
00623 if(lt >= typeCount)
00624 lt = typeCount - 1;
00625 }
00626
00627 _logType = types[lt];
00628 }
00629 }
00630 else
00631 {
00632 _logType = logType;
00633 }
00634
00635 connect();
00636 }
00637
00638
00639 LogLevel Log::getLogLevel(void)
00640 {
00641 return _logLevel;
00642 }
00643
00644
00649 void Log::setLogLevel(LogLevel logLevel, bool force)
00650 {
00651 static Char8 *levelnames[] =
00652 {
00653 "log",
00654 "fatal",
00655 "warning",
00656 "notice",
00657 "info",
00658 "debug",
00659 NULL
00660 };
00661
00662 static LogLevel levels [] =
00663 {
00664 LOG_LOG,
00665 LOG_FATAL,
00666 LOG_WARNING,
00667 LOG_NOTICE,
00668 LOG_INFO,
00669 LOG_DEBUG
00670 };
00671
00672 static Int32 levelCount = sizeof(levels) / sizeof(LogLevel);
00673
00674 Char8 *el;
00675 Int32 ll;
00676 Int32 i;
00677
00678 if(!force && (this == osgLogP) && (el = getenv("OSG_LOG_LEVEL")))
00679 {
00680 osgLog() << "OSGLog::setLogLevel: overriden by envvar OSG_LOG_LEVEL '"
00681 << el << "'." << std::endl;
00682
00683 if(sscanf(el, "%d", &ll) != 1)
00684 {
00685 for(i = 0; levelnames[i]; i++)
00686 {
00687 if(!stringcasecmp(el, levelnames[i]))
00688 {
00689 _logLevel = levels[i];
00690 break;
00691 }
00692 }
00693
00694 if(! levelnames[i])
00695 {
00696 _logLevel = LOG_DEBUG;
00697
00698 osgLog() << "Log::setLogLevel: couldn't interpret envvar, "
00699 << "set to LOG_DEBUG!"
00700 << std::endl;
00701 }
00702 }
00703 else
00704 {
00705 if (ll < 0)
00706 {
00707 ll = 0;
00708 }
00709 else
00710 {
00711 if (ll >= levelCount)
00712 ll = levelCount - 1;
00713 }
00714
00715 _logLevel = levels[ll];
00716 }
00717 }
00718 else
00719 {
00720 _logLevel = logLevel;
00721 }
00722
00723 connect() ;
00724 }
00725
00726
00731 void Log::setLogFile(const Char8 *fileName, bool force)
00732 {
00733 const Char8 *name;
00734
00735 #ifdef OSG_STREAM_HAS_ISOPEN
00736 if(_fileStream.is_open())
00737 #else
00738 if(_fileStream.rdbuf()->is_open())
00739 #endif
00740 {
00741 _fileStream.close();
00742 }
00743
00744 if(!force && (this == osgLogP) && (name = getenv("OSG_LOG_FILE")))
00745 {
00746 osgLog() << "Log::setLogFile: overriden by envvar OSG_LOG_FILE '"
00747 << name << "'." << std::endl;
00748 }
00749 else
00750 {
00751 name = fileName;
00752 }
00753
00754 if(name && *name)
00755 {
00756 _fileStream.open(name, std::ios::out);
00757
00758 #ifdef OSG_STREAM_HAS_ISOPEN
00759 if(_fileStream.is_open())
00760 #else
00761 if(_fileStream.rdbuf()->is_open())
00762 #endif
00763 {
00764 _logType = LOG_FILE;
00765 connect();
00766 }
00767 }
00768 }
00769
00770
00774 void Log::doLog(const Char8 * format, ...)
00775 {
00776 static Char8 *buffer = NULL;
00777 static int buffer_size = 0;
00778 va_list args;
00779
00780 va_start( args, format );
00781
00782 #if defined(OSG_HAS_VSNPRINTF) && !defined(__sgi)
00783 int count;
00784
00785 if(!buffer)
00786 {
00787 buffer_size = 8;
00788 buffer = new Char8[buffer_size];
00789 }
00790
00791
00792
00793
00794 count = vsnprintf(buffer, buffer_size, format, args);
00795
00796 while(count >= buffer_size || count == -1)
00797 {
00798 buffer_size = osgMax(buffer_size * 2, count + 1);
00799 if(buffer) delete [] buffer;
00800 buffer = new Char8[buffer_size];
00801 va_start( args, format );
00802 count = vsnprintf(buffer, buffer_size, format, args);
00803 }
00804 #else
00805 if(buffer_size < 8192)
00806 {
00807 buffer_size = 8192;
00808 if(buffer) delete [] buffer;
00809 buffer = new Char8[buffer_size];
00810 }
00811 vsprintf(buffer, format, args);
00812 #endif
00813
00814
00815
00816
00817 std::ostream& os = *this;
00818 os << buffer;
00819 os << std::flush;
00820
00821 va_end(args);
00822 }
00823
00824
00828 void Log::connect(void)
00829 {
00830 Int32 i;
00831
00832 #ifndef OSG_STREAM_RDBUF_HAS_PARAM
00833 switch(_logType)
00834 {
00835 case LOG_STDOUT:
00836 this->bp = std::cout.rdbuf();
00837 break;
00838 case LOG_STDERR:
00839 this->bp = std::cerr.rdbuf();
00840 break;
00841 case LOG_FILE:
00842 this->bp = _fileStream.rdbuf();
00843 break;
00844 case LOG_BUFFER:
00845 this->bp = _logBuf;
00846 break;
00847 case LOG_NONE:
00848 default:
00849 this->bp = _nilStreamP->rdbuf();
00850 break;
00851 }
00852 #else
00853 switch(_logType)
00854 {
00855 case LOG_STDOUT:
00856 this->rdbuf(std::cout.rdbuf());
00857 break;
00858 case LOG_STDERR:
00859 this->rdbuf(std::cerr.rdbuf());
00860 break;
00861 case LOG_FILE:
00862 this->rdbuf(_fileStream.rdbuf());
00863 break;
00864 case LOG_BUFFER:
00865 this->rdbuf(&_logBuf);
00866 break;
00867 case LOG_NONE:
00868 default:
00869 this->rdbuf(_nilbufP);
00870 break;
00871 }
00872 #endif
00873
00874 for(i = 0; i < int(sizeof(_streamVec)/sizeof(std::ostream*)); ++i)
00875 {
00876 if (i <= _logLevel)
00877 {
00878 _streamVec[i]->setrdbuf(this->rdbuf());
00879 }
00880 else
00881 {
00882 #ifdef OSG_HAS_NILBUF
00883 _streamVec[i]->setrdbuf(_nilbufP);
00884 #else
00885 _streamVec[i]->setrdbuf(_nilStreamP->rdbuf());
00886 #endif
00887 }
00888 }
00889 }
00890
00891
00909 OSG_BEGIN_NAMESPACE
00910
00911 OSG_BASE_DLLMAPPING LogP osgLogP = NULL;
00912
00913 OSG_END_NAMESPACE
00914
00915
00916 void OSG::doInitLog(void)
00917 {
00918 #ifdef OSG_HAS_NILBUF
00919 if(Log::_nilbufP == NULL)
00920 Log::_nilbufP = new Log::nilbuf();
00921 #else
00922 if(Log::_nilstreamP == NULL)
00923 Log::_nilstreamP = new std::fstream("/dev/null", std::ios::out);
00924 #endif
00925
00926 if(osgLogP == NULL)
00927 {
00928 osgLogP = new Log();
00929
00930 osgLogP->setLogLevel(OSG_DEFAULT_LOG_LEVEL);
00931 osgLogP->setLogFile (NULL );
00932 osgLogP->setLogType (OSG_DEFAULT_LOG_TYPE );
00933 }
00934 }