#include #include #include #include #include "ICOMETLog.hxx" COMET::ICOMETLog::ErrorPriority COMET::ICOMETLog::fErrorPriority = COMET::ICOMETLog::ErrorLevel; COMET::ICOMETLog::LogPriority COMET::ICOMETLog::fLogPriority = COMET::ICOMETLog::LogLevel; std::ostream* COMET::ICOMETLog::fDebugStream = NULL; std::ostream* COMET::ICOMETLog::fLogStream = NULL; std::map COMET::ICOMETLog::fErrorTraces; std::map COMET::ICOMETLog::fLogTraces; int COMET::ICOMETLog::fIndentation = 0; COMET::ICOMETLog::ICOMETLog() { } COMET::ICOMETLog::~ICOMETLog() { } void COMET::ICOMETLog::SetDebugLevel(const char* trace, COMET::ICOMETLog::ErrorPriority level) { fErrorTraces[trace] = level; } COMET::ICOMETLog::ErrorPriority COMET::ICOMETLog::GetDebugLevel(const char* trace) { std::map::iterator elem = fErrorTraces.find(trace); if (elem == fErrorTraces.end()) return fErrorPriority; return elem->second; } namespace { std::string MakeTimeStamp() { std::string stamp = "Unknown Time"; time_t t = time(NULL); struct tm *local = localtime(&t); if (!local) return stamp; char localTime[80]; if (!strftime(localTime,sizeof(localTime),"%c",local)) return stamp; struct tm *utc = gmtime(&t); if (!utc) return stamp; char utcTime[80]; if (!strftime(utcTime,sizeof(utcTime),"%Y-%m-%d %H:%M (UTC)",utc)) return stamp; stamp = localTime; stamp += " ["; stamp += utcTime; stamp += "]"; return stamp; } } void COMET::ICOMETLog::SetDebugStream(std::ostream* err) { COMET::ICOMETLog::fDebugStream = err; if (!fDebugStream) return; std::ofstream* ofile = dynamic_cast(err); if (ofile && !(ofile->is_open())) { fDebugStream = NULL; COMETSevere("Debug stream is not open."); } *fDebugStream << std::endl << "##################################################" << std::endl << "# ERROR LOG STARTS AT: " << MakeTimeStamp() << std::endl << "##################################################" << std::endl << std::endl; } std::ostream& COMET::ICOMETLog::GetDebugStream() { if (!COMET::ICOMETLog::fDebugStream ) return GetLogStream(); return *COMET::ICOMETLog::fDebugStream; } void COMET::ICOMETLog::SetLogLevel(const char* trace, COMET::ICOMETLog::LogPriority level) { fLogTraces[trace] = level; } COMET::ICOMETLog::LogPriority COMET::ICOMETLog::GetLogLevel(const char* trace) { std::map::iterator elem = fLogTraces.find(trace); if (elem == fLogTraces.end()) return fLogPriority; return elem->second; } void COMET::ICOMETLog::SetLogStream(std::ostream* log) { COMET::ICOMETLog::fLogStream = log; if (!fLogStream) return; std::ofstream* ofile = dynamic_cast(log); if (ofile && !(ofile->is_open())) { fLogStream = NULL; COMETSevere("Log stream is not open."); } *fLogStream << std::endl << "##################################################" << std::endl << "# LOG STARTS AT: " << MakeTimeStamp() << std::endl << "##################################################" << std::endl << std::endl; } std::ostream& COMET::ICOMETLog::GetLogStream() { if (!COMET::ICOMETLog::fLogStream) return std::cout; return *COMET::ICOMETLog::fLogStream; } void COMET::ICOMETLog::SetIndentation(int i) { COMET::ICOMETLog::fIndentation = std::max(i,0); } void COMET::ICOMETLog::IncreaseIndentation() { ++COMET::ICOMETLog::fIndentation; } void COMET::ICOMETLog::DecreaseIndentation() { if (COMET::ICOMETLog::fIndentation>0) --COMET::ICOMETLog::fIndentation; } void COMET::ICOMETLog::ResetIndentation() { COMET::ICOMETLog::fIndentation = 0; } std::string COMET::ICOMETLog::MakeIndent() { if (fIndentation<1) return ""; std::string indent = ""; for (int i=0; iis_open()) return output; return NULL; } bool ReadConfigurationFile(const char* config) { std::ifstream input(config); if (!input.is_open()) return false; int inputLine = 0; for (;;) { std::string line; std::getline(input,line); if (input.eof()) break; // Save the current line number and cache the value so error // messages can be printed later. std::string cache(line); ++inputLine; // Strip the comments out of the file. std::string::size_type position = line.find("#"); if (position != std::string::npos) line.erase(position); // Strip the white space at the beginning of the line. line.erase(0,line.find_first_not_of("\t ")); // Skip lines that are too short. if (line.size()==0) continue; // Split the line into fields and a value. position = line.find("="); if (position == std::string::npos) { // Houston, we have a problem... There isn't a value. std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Configuration line missing an '='" << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } // Split the value off the end of the line. std::string value = line.substr(position+1); line.erase(position); // Strip the white space at the beginning of the value. value.erase(0,value.find_first_not_of("\t ")); // Strip the white space at the end of the value. position = value.find_last_not_of("\t "); if (position != std::string::npos) value.erase(position+1); // Strip the white space at the end of the fields. position = line.find_last_not_of("\t "); if (position != std::string::npos) line.erase(position+1); // Split the remaining line in to fields. std::vector fields; for (;;) { position = line.find("."); if (position == std::string::npos) { fields.push_back(line); break; } fields.push_back(line.substr(0,position)); line.erase(0,position+1); } // Process the fields and value. if (fields.size() == 2 && fields[0] == "log" && fields[1] == "file") { // Set the log file name. std::ostream* str = StreamPointer(value); if (!str) { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Cannot open log stream." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } COMET::ICOMETLog::SetLogStream(str); } else if (fields.size() == 2 && fields[0] == "error" && fields[1] == "file") { // Set the error file name. std::ostream* str = StreamPointer(value); if (!str) { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Cannot open error stream." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } COMET::ICOMETLog::SetDebugStream(str); } else if (fields.size() == 3 && fields[0] == "log" && fields[1] == "default" && fields[2] == "level") { // Set the default log level. COMET::ICOMETLog::LogPriority level; if (!TranslateLogLevel(value,level)) { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Unknown log level name." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } COMET::ICOMETLog::SetLogLevel(level); } else if (fields.size() == 3 && fields[0] == "error" && fields[1] == "default" && fields[2] == "level") { // Set the default error level. COMET::ICOMETLog::ErrorPriority level; if (!TranslateErrorLevel(value,level)) { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Unknown error level name." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } COMET::ICOMETLog::SetDebugLevel(level); } else if (fields.size() == 3 && fields[0] == "log" && fields[2] == "level") { // Set the log level. COMET::ICOMETLog::LogPriority level; if (!TranslateLogLevel(value,level)) { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Unknown log level name." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } COMET::ICOMETLog::SetLogLevel(fields[1].c_str(),level); } else if (fields.size() == 3 && fields[0] == "error" && fields[2] == "level") { // Set the error level. COMET::ICOMETLog::ErrorPriority level; if (!TranslateErrorLevel(value,level)) { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Unknown error level name." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; continue; } COMET::ICOMETLog::SetDebugLevel(fields[1].c_str(),level); } else { std::cerr << "WARNING: " << config << ":" << inputLine << ": " << "Unknown command." << std::endl; std::cerr << " Line: <" << cache << ">" << std::endl; std::cerr << " Configuration line has been skip" << std::endl; } } return true; } } void COMET::ICOMETLog::Configure(const char* conf) { // Try to read a local configuration file. ReadConfigurationFile("./cometlog.config"); if (conf) { bool success = ReadConfigurationFile(conf); if (!success) COMETLog("COMETLog configuration file was not read."); } }