Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:39

0001 /*
0002  * Copyright (c) 2019 Opticks Team. All Rights Reserved.
0003  *
0004  * This file is part of Opticks
0005  * (see https://bitbucket.org/simoncblyth/opticks).
0006  *
0007  * Licensed under the Apache License, Version 2.0 (the "License"); 
0008  * you may not use this file except in compliance with the License.  
0009  * You may obtain a copy of the License at
0010  *
0011  *   http://www.apache.org/licenses/LICENSE-2.0
0012  *
0013  * Unless required by applicable law or agreed to in writing, software 
0014  * distributed under the License is distributed on an "AS IS" BASIS, 
0015  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
0016  * See the License for the specific language governing permissions and 
0017  * limitations under the License.
0018  */
0019 
0020 #include <cstdlib>
0021 #include <cstring>
0022 #include <cassert>
0023 #include <iostream>
0024 #include <algorithm>
0025 #include <string>
0026 
0027 
0028 #include "SLOG.hh"
0029 #include "ssys.h"
0030 #include "s_time.h"
0031 #include "sproc.h"
0032 
0033 #include "SASCII.hh"
0034 
0035 SLOG* SLOG::instance = NULL ; 
0036 
0037 const int SLOG::MAXARGC = 100 ;  
0038 
0039 
0040 /**
0041 
0042 
0043 plog enum levels
0044 
0045  none = 0, 
0046  fatal = 1,
0047  error = 2,
0048  warning = 3,
0049  info = 4,
0050  debug = 5,
0051  verbose = 6 
0052 
0053 **/
0054 
0055 template<int IDX>
0056 plog::Severity SLOG::MaxSeverity(plog::Logger<IDX>* logger)
0057 {
0058     return logger ? logger->getMaxSeverity() : plog::none ; 
0059 }
0060 template<int IDX>
0061 const char* SLOG::MaxSeverityString(plog::Logger<IDX>* logger)
0062 {
0063     return  plog::severityToString(SLOG::MaxSeverity<IDX>(logger)) ; 
0064 }
0065 
0066 
0067 
0068 template<int IDX>
0069 std::string SLOG::Desc(plog::Logger<IDX>* logger)
0070 {
0071     std::stringstream ss ; 
0072     ss << " logger " << logger
0073        << " SLOG::MaxSeverity<IDX>(logger) " << SLOG::MaxSeverity<IDX>(logger)
0074        << " SLOG::MaxSeverityString<IDX>(logger) " << SLOG::MaxSeverityString<IDX>(logger)
0075        ; 
0076     std::string str = ss.str(); 
0077     return str ; 
0078 }
0079 
0080 
0081 
0082 
0083 
0084 template<int IDX>
0085 std::string SLOG::Desc()
0086 {
0087     plog::Logger<IDX>* lib_logger = plog::get<IDX>(); 
0088     return Desc(lib_logger) ; 
0089 }
0090 
0091 std::string SLOG::banner() const 
0092 {
0093     const char* bin = exename() ; 
0094     int VERSION = ssys::getenvint("VERSION", 0 );  
0095     std::stringstream ss ; 
0096     ss << "SLOG::banner" 
0097        << " " << ( bin ? bin : "-" )
0098        << " " << s_time::Stamp() 
0099        << " " << s_time::EpochSeconds() 
0100        << " V" << VERSION 
0101        ;
0102 
0103     std::string str = ss.str(); 
0104     return str ; 
0105 }
0106 std::string SLOG::Banner()
0107 {
0108     return instance ? instance->banner() : "-" ; 
0109 }
0110 
0111 
0112 template std::string SLOG::Desc<0>(plog::Logger<0>* ) ; 
0113 template std::string SLOG::Desc<0>() ; 
0114 
0115 std::string SLOG::Flags()
0116 {
0117     std::stringstream ss ; 
0118     ss 
0119 #ifdef PLOG_LOCAL
0120        << " PLOG_LOCAL "
0121 #else
0122        << " NOT:PLOG_LOCAL "
0123 #endif
0124 #ifdef PLOG_GLOBAL
0125        << " PLOG_GLOBAL "
0126 #else
0127        << " NOT:PLOG_GLOBAL "
0128 #endif
0129        ; 
0130     std::string s = ss.str(); 
0131     return s ; 
0132 }
0133 
0134 
0135 void SLOG::Dump()
0136 {
0137     LOG(none)    << " LOG(none) " ; 
0138     LOG(fatal)   << " LOG(fatal) " ; 
0139     LOG(error)   << " LOG(error) " ; 
0140     LOG(warning) << " LOG(warning) " ; 
0141     LOG(info)    << " LOG(info) " ; 
0142     LOG(debug)   << " LOG(debug) " ; 
0143     LOG(verbose) << " LOG(verbose) " ; 
0144 }
0145 
0146 
0147 
0148 
0149 
0150 plog::Severity SLOG::Delta(plog::Severity level_, int delta)
0151 {
0152     int level = (int)level_ + delta ; 
0153     if(level < (int)fatal)   level = (int)fatal ; 
0154     if(level > (int)verbose) level = (int)verbose ; 
0155     return (plog::Severity)level ; 
0156 }
0157 
0158 /**
0159 SLOG::EnvLevel
0160 ----------------
0161 
0162 Used to make static logging LEVEL initializers sensitive to envvars
0163 holding logging level strings::
0164 
0165     const plog::Severity ClassName::LEVEL = SLOG::EnvLevel("ClassName", "DEBUG") ;  
0166 
0167 Static initializers run very early, prior to logging being setup.
0168 
0169 **/
0170 
0171 plog::Severity SLOG::EnvLevel( const char* key, const char* fallback)
0172 {
0173     const char* level = ssys::getenvvar(key, fallback);  
0174     const char* upper_level = SASCII::ToUpper(level); 
0175     plog::Severity severity = plog::severityFromString(upper_level) ;
0176 
0177     if(strcmp(level, fallback) != 0)
0178     {
0179         std::cerr 
0180             << "SLOG::EnvLevel"
0181             << " adjusting loglevel by envvar  "
0182             << " key " << key  
0183             << " level " << level
0184             << " fallback " << fallback
0185             << " upper_level " << upper_level
0186             << std::endl 
0187             ;     
0188     }
0189     return severity ; 
0190 } 
0191 
0192 
0193 
0194 
0195 void SLOG::_dump(const char* msg, int argc, char** argv)
0196 {
0197     std::cerr <<  msg
0198               << " argc " << argc ;
0199 
0200     for(int i=0 ; i < argc ; i++) std::cerr << argv[i] ; 
0201     std::cerr << std::endl ;               
0202 }
0203 
0204 int SLOG::_parse(int argc, char** argv, const char* fallback)
0205 {
0206     // Parse arguments case insensitively looking for --VERBOSE --info --error etc.. returning global logging level
0207 
0208     assert( argc < MAXARGC && " argc sanity check fail "); 
0209 
0210     std::string ll = fallback ; 
0211     for(int i=1 ; i < argc ; ++i )
0212     {
0213         std::string arg(argv[i] ? argv[i] : "");
0214         std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
0215         if(arg.compare("--trace")==0)   ll = "VERBOSE" ; 
0216         if(arg.compare("--verbose")==0) ll = "VERBOSE" ; 
0217         if(arg.compare("--debug")==0)   ll = "DEBUG" ; 
0218         if(arg.compare("--info")==0)    ll = "INFO" ; 
0219         if(arg.compare("--warning")==0) ll = "WARNING" ; 
0220         if(arg.compare("--error")==0)   ll = "ERROR" ; 
0221         if(arg.compare("--fatal")==0)   ll = "FATAL" ;
0222 
0223         // severityFromString uses first char 
0224     }
0225      
0226     std::transform(ll.begin(), ll.end(), ll.begin(), ::toupper);
0227     plog::Severity severity = plog::severityFromString(ll.c_str()) ;
0228 
0229     int level = static_cast<int>(severity); 
0230 
0231     //_dump("SLOG::parse", argc, argv );
0232 
0233     return level ;  
0234 }
0235 
0236 
0237 /**
0238 SLOG::_logpath_parse_problematic
0239 --------------------------------------
0240 
0241 Constructs logfile path based on executable name argv[0] with .log appended 
0242 
0243 This approach is problematic as when running from an absolute 
0244 path such as with::
0245 
0246     gdb $(which OKTest)
0247 
0248 This will yield a logpath within the directory where executables
0249 are installed which presents a permission problems with shared installs.
0250 
0251 **/
0252 
0253 const char* SLOG::_logpath_parse_problematic(int argc, char** argv)
0254 {
0255     assert( argc < MAXARGC && " argc sanity check fail "); 
0256     std::string lp(argc > 0 ? argv[0] : "default") ; 
0257     lp += ".log" ; 
0258     return strdup(lp.c_str());
0259 }
0260 
0261 
0262 /**
0263 SLOG::_logpath()
0264 ------------------
0265 
0266 This uses just the executable name with .log appended 
0267 
0268 **/
0269 
0270 const char* SLOG::_logpath()
0271 {
0272     const char* exename = sproc::ExecutableName() ; 
0273     std::string lp(exename) ; 
0274     lp += ".log" ; 
0275     return strdup(lp.c_str());
0276 }
0277 
0278 
0279 
0280 
0281 /**
0282 SLOG::_prefixlevel_parse
0283 ---------------------------
0284 
0285 Example commandline::
0286 
0287    --okcore info --sysrap error --brap trace --npy trace
0288 
0289 Parse commandline to find project logging level  
0290 looking for a single project prefix, eg 
0291 with the below commandline and prefix of sysrap
0292 the level "error" should be set.
0293 
0294 When no level is found the fallback level is used.
0295      
0296 Both prefix and the arguments are lowercased before comparison.
0297 
0298 
0299 **/
0300 
0301 int SLOG::_prefixlevel_parse(int argc, char** argv, const char* fallback, const char* prefix)
0302 {
0303 
0304     assert( argc < MAXARGC && " argc sanity check fail "); 
0305 
0306     std::string pfx(prefix);
0307     std::transform(pfx.begin(), pfx.end(), pfx.begin(), ::tolower);
0308     std::string apfx("--");
0309     apfx += pfx ;  
0310 
0311     std::string ll(fallback) ;
0312     for(int i=1 ; i < argc ; ++i )
0313     {
0314         char* ai = argv[i] ;
0315         char* aj = i + 1 < argc ? argv[i+1] : NULL ; 
0316 
0317         std::string arg(ai ? ai : "");
0318         std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
0319         //std::cerr << arg << std::endl ; 
0320 
0321         if(arg.compare(apfx) == 0 && aj != NULL ) ll.assign(aj) ;
0322     }
0323 
0324     std::transform(ll.begin(), ll.end(), ll.begin(), ::toupper);
0325 
0326     const char* llc = ll.c_str();
0327     plog::Severity severity = strcmp(llc, "TRACE")==0 ? plog::severityFromString("VERB") : plog::severityFromString(llc) ;
0328     int level = static_cast<int>(severity); 
0329 
0330     //_dump("SLOG::prefix_parse", argc, argv );
0331 
0332     return level ; 
0333 }
0334 
0335 
0336 
0337 
0338 int SLOG::parse(plog::Severity _fallback)
0339 {
0340     const char* fallback = _name(_fallback);
0341     return parse(fallback);
0342 }
0343 int SLOG::parse(const char* fallback)
0344 {
0345     int ll = _parse(args._argc, args._argv, fallback);
0346 
0347 #ifdef SLOG_DBG
0348     std::cerr << "SLOG::parse"
0349               << " fallback " << fallback
0350               << " level " << ll 
0351               << " name " << _name(ll)
0352               << std::endl ;
0353 #endif
0354 
0355     return ll ; 
0356 }
0357 
0358 
0359 int SLOG::prefixlevel_parse(int _fallback, const char* prefix)
0360 {
0361     plog::Severity fallback = static_cast<plog::Severity>(_fallback); 
0362     return prefixlevel_parse(fallback, prefix) ; 
0363 }
0364 
0365 int SLOG::prefixlevel_parse(plog::Severity _fallback, const char* prefix)
0366 {
0367     const char* fallback = _name(_fallback);
0368     return prefixlevel_parse(fallback, prefix) ; 
0369 }
0370 
0371 
0372 
0373 
0374 /**
0375 SLOG::prefixlevel_parse
0376 -------------------------
0377 
0378 This provides loglevel control at the granularity of a library 
0379 controlled by commandline options. BUT this has proved far too coarse 
0380 a control to be useful, and has not been used in many years. 
0381 
0382 Hence this prefixlevel_parse functionality could be removed ?
0383 
0384 Controlling logging at the level of classes/structs 
0385 has proved very useful. 
0386 
0387 **/
0388 
0389 
0390 int SLOG::prefixlevel_parse(const char* fallback, const char* prefix)
0391 {
0392     int ll =  _prefixlevel_parse(args._argc, args._argv, fallback, prefix);
0393 
0394 #ifdef SLOG_DBG
0395     std::cerr << "SLOG::prefixlevel_parse"
0396               << " fallback " << fallback
0397               << " prefix " << prefix 
0398               << " level " << ll 
0399               << " name " << _name(ll)
0400               << std::endl ;
0401 #endif
0402 
0403     return ll ; 
0404 }
0405 
0406 
0407 
0408 const char* SLOG::_name(int level)
0409 {
0410    plog::Severity severity  = static_cast<plog::Severity>(level); 
0411    return plog::severityToString(severity);
0412 }
0413 const char* SLOG::_name(plog::Severity severity)
0414 {
0415    return plog::severityToString(severity);
0416 }
0417 
0418 const char* SLOG::name()
0419 {
0420    plog::Severity severity  = static_cast<plog::Severity>(level); 
0421    return _name(severity);
0422 }
0423 
0424 const char* SLOG::exename() const 
0425 {
0426     return args.exename(); 
0427 }
0428 const char* SLOG::cmdline() const 
0429 {
0430     return args.cmdline(); 
0431 }
0432 
0433 
0434 const char* SLOG::get_arg_after(const char* option, const char* fallback) const 
0435 {
0436     return args.get_arg_after(option, fallback); 
0437 }
0438 int SLOG::get_int_after(const char* option, const char* fallback) const 
0439 {
0440     return args.get_int_after(option, fallback); 
0441 }
0442 bool SLOG::has_arg(const char* arg) const 
0443 {
0444     return args.has_arg(arg); 
0445 }
0446 
0447 
0448 
0449 
0450 
0451 
0452 SLOG::SLOG(const char* name, const char* fallback, const char* prefix)
0453     :
0454     args(name, "OPTICKS_LOG_ARGS" , ' '),   // when argc_ is 0 the named envvar is checked for arguments instead 
0455     level(info),
0456     filename(_logpath()),
0457     maxFileSize(ssys::getenvint("OPTICKS_LOG_MAXFILESIZE", 5000000)),
0458     maxFiles(ssys::getenvint("OPTICKS_LOG_MAXFILES", 10))
0459 {
0460     init(fallback, prefix); 
0461 }
0462 
0463 SLOG::SLOG(int argc_, char** argv_, const char* fallback, const char* prefix)
0464     :
0465     args(argc_, argv_, "OPTICKS_LOG_ARGS" , ' '),   // when argc_ is 0 the named envvar is checked for arguments instead 
0466     level(info),
0467     filename(_logpath()),
0468     maxFileSize(ssys::getenvint("OPTICKS_LOG_MAXFILESIZE", 5000000)),
0469     maxFiles(ssys::getenvint("OPTICKS_LOG_MAXFILES", 10))
0470 {
0471     init(fallback, prefix); 
0472 }
0473 
0474 
0475 void SLOG::init(const char* fallback, const char* prefix)
0476 {
0477     level = prefix == NULL ?  parse(fallback) : prefixlevel_parse(fallback, prefix ) ;    
0478     assert( instance == NULL && "ONLY EXPECTING A SINGLE SLOG INSTANCE" );
0479     instance = this ; 
0480     if(getenv("SLOG")) std::cout << "SLOG::init " << desc() << std::endl ; 
0481 }
0482 
0483 std::string SLOG::desc() const 
0484 {
0485     std::stringstream ss ; 
0486     ss << "SLOG::desc"
0487        << " level " << plog::severityToString((plog::Severity)level)  
0488        << " filename " << filename
0489        << " maxFileSize " << maxFileSize
0490        << " maxFiles " << maxFiles 
0491        ;
0492     std::string s = ss.str(); 
0493     return s ; 
0494 }
0495 
0496