#ifndef LOGGER_HPP_INCLUDED #define LOGGER_HPP_INCLUDED #include #include #include #include #include #include extern int verbose; enum LoggingLevels { LOG_ERROR, LOG_INFO, LOG_VERBOSE, LOG_DEBUG }; #define LogDebug(s, ...) \ if ( verbose >= LOG_DEBUG ) printf(s, ##__VA_ARGS__); #define LogMoreInfo(s, ...) \ if ( verbose >= LOG_VERBOSE ) printf(s, ##__VA_ARGS__); #define LogInfo(s, ...) \ if ( verbose >= LOG_INFO ) printf(s, ##__VA_ARGS__); #define LogError(s, ...) \ if ( verbose >= LOG_ERROR ) { printf("%s, %s(), %d: ", __FILE__, __func__, __LINE__); printf(s, ##__VA_ARGS__); } /* Imported from Astrant: Questions/Suggestions mail nick@astrant.net */ struct LoggingBase { protected: LoggingBase(std::ostream & out, LoggingLevels level) : out(out) , level(level) {} virtual ~LoggingBase(){} bool shouldSkip(){ return verbose < level; } std::ostream & out; LoggingLevels level; }; struct Logger : public LoggingBase { Logger(std::ostream& logging_stream_, LoggingLevels level, std::string prefix_ = "") : LoggingBase(logging_stream_, level) , event_map() , event_name_stack() , prefix(prefix_) {} void log(std::string what){ if (shouldSkip()) return; out << get_prefix() << "(" << what << ") took place at (" << boost::posix_time::microsec_clock::local_time() << std::endl; } void start(std::string what){ if (shouldSkip()) return; Event e(what); EventMap::iterator it = event_map.find(what); if(it != event_map.end()){ out << get_prefix() << "WARNING: Overwriting event(" << e.name << "), did you forget to call stop()?"; } else { event_name_stack.push(what); } event_map.insert(it, std::make_pair(what, e)); } void stop() { if (shouldSkip()) return; assert(!event_name_stack.empty()); stop(event_name_stack.top()); } private: void stop(std::string what){ EventMap::iterator it = event_map.find(what); if(it == event_map.end()){ out << get_prefix() << "WARNING: No such, or already stopped, event(" << what << "), did you forget to call start()?"; } else { it->second.end = boost::posix_time::microsec_clock::local_time(); log_event(it->second); event_map.erase(it); } event_name_stack.pop(); } struct Event { Event(std::string const & name) : start(boost::posix_time::microsec_clock::local_time()) , end(boost::posix_time::microsec_clock::local_time()) , name(name) {} boost::posix_time::ptime start; boost::posix_time::ptime end; std::string name; }; // A map containing strings -> Event, used by start() and stop() typedef std::map EventMap; EventMap event_map; // A stack used by 0-parameter stop() to stop the last start()ed event. std::stack event_name_stack; std::string prefix; void log_event(Event const& e){ out << get_prefix() << "Event(" << e.name << ") started at (" << e.start << ") ended at (" << e.end << ") duration (" << e.end - e.start << " ms) " << std::endl; } std::string get_prefix() const { if(prefix == std::string("")){ return prefix; } else { return prefix + ": "; } } }; /* My progressbar class (as seen on github) */ struct Progressbar : public LoggingBase { Progressbar(std::ostream & out, LoggingLevels level, std::string prefix = "") : LoggingBase(out, level) , prefix(prefix) { if (shouldSkip()) return; show(0, 1, ' '); } ~Progressbar(){ if (shouldSkip()) return; if (!std::uncaught_exception()) show(1, 1, '='); out << std::endl; } template void show(T const & progress, T const & max, char delim = '>'){ if (shouldSkip()) return; out << "\r"; size_t width = 79; // default terminal size :D width -= prefix.size(); width -= 3; // [, > and ] if (prefix != "") { width -= 1; out << prefix << ' '; } double ratio = (double) progress / (double) max; size_t length = width * ratio; std::string fill(length, '='); std::string empty(width - length, ' '); out << '[' << fill << delim << empty << ']' << std::flush; } private: std::string prefix; }; struct ProgressIndicator : public LoggingBase { ProgressIndicator(std::ostream & out, LoggingLevels level, std::string prefix = "") : LoggingBase(out, level) , prefix(prefix) , wave("`*-,_,-*`") , previous_time(boost::posix_time::microsec_clock::local_time() - boost::posix_time::seconds(1.0)) , progress(0) { show(); } ~ProgressIndicator(){ if (shouldSkip()) return; if (!std::uncaught_exception()) show("="); out << std::endl; } void show(std::string const & alt_wave = ""){ if (shouldSkip()) return; boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); if(now - previous_time < boost::posix_time::milliseconds(50.0)) return; out << "\r"; size_t width = 79; // default terminal size :D width -= 2; if(prefix != ""){ width -= prefix.size() + 1; out << prefix << ' '; } std::string const & wave_to_use = (alt_wave == "") ? wave : alt_wave; out << '['; for(unsigned int i = 0; i < width; ++i){ out << wave_to_use[(i + progress) % wave_to_use.size()]; } out << ']' << std::flush; previous_time = now; ++progress; if(progress >= wave.size()) progress = 0; } private: std::string prefix; std::string wave; boost::posix_time::ptime previous_time; unsigned int progress; }; extern Logger logger; #endif // LOGGER_HPP_INCLUDED