* Refactoring of tlm_target to be used by reference and by inheritance * sr_report has been added as well as a report handler to sysc::Loggerpull/6/head
@ -0,0 +1,6 @@ | |||
[submodule "incl/sr_signal"] | |||
path = incl/sr_signal | |||
url = https://github.com/socrocket/sr_signal.git | |||
[submodule "incl/sr_report"] | |||
path = incl/sr_report | |||
url = https://github.com/socrocket/sr_report.git |
@ -1,38 +0,0 @@ | |||
/* | |||
* logging.h | |||
* | |||
* Created on: Nov 24, 2016 | |||
* Author: developer | |||
*/ | |||
#ifndef INCL_SYSC_LOGGING_H_ | |||
#define INCL_SYSC_LOGGING_H_ | |||
#include <util/logging.h> | |||
#include <systemc> | |||
namespace logging { | |||
template <typename T> | |||
class ScLog: public Log<T>{ | |||
public: | |||
ScLog(){}; | |||
std::ostringstream& Get(LogLevel level = info){ | |||
this->os << "- " << NowTime(); | |||
this->os << " " << Log<T>::ToString(level) << " - ["<<sc_core::sc_time_stamp()<<"] "; | |||
Log<T>::getLastLogLevel()=level; | |||
return this->os; | |||
}; | |||
}; | |||
class FILELOG_DECLSPEC ScLogger : public ScLog<Output2FILE> {}; | |||
#undef LOG | |||
#define LOG(level) \ | |||
if (level > FILELOG_MAX_LEVEL) ;\ | |||
else if (level > logging::Logger::ReportingLevel() || !logging::Output2FILE::Stream()) ; \ | |||
else logging::ScLogger().Get(level) | |||
} | |||
#endif /* INCL_SYSC_LOGGING_H_ */ |
@ -0,0 +1,69 @@ | |||
/******************************************************************************* | |||
* Copyright 2016 MINRES Technologies GmbH | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*******************************************************************************/ | |||
/* | |||
* logging.h | |||
* | |||
* Created on: Nov 24, 2016 | |||
* Author: developer | |||
*/ | |||
#ifndef _SYSC_REPORT_H_ | |||
#define _SYSC_REPORT_H_ | |||
#include <util/logging.h> | |||
#include <sysc/utilities.h> | |||
#include <sysc/utils/sc_report.h> | |||
#include <sstream> | |||
#include <iomanip> | |||
namespace sysc { | |||
void init_logging(); | |||
template <typename T> | |||
class Log: public logging::Log<T>{ | |||
public: | |||
Log(){}; | |||
std::ostringstream& get(logging::log_level level = logging::info){ | |||
this->os << /*"- " <<*/ logging::now_time(); | |||
this->os << " " << logging::Log<T>::to_string(level) << " - ["<<std::setw(16)<<sc_core::sc_time_stamp()<<"] "; | |||
logging::Log<T>::get_last_log_level()=level; | |||
return this->os; | |||
}; | |||
}; | |||
class FILELOG_DECLSPEC Logger : public Log<logging::Output2FILE> { | |||
static std::once_flag once; | |||
public: | |||
static logging::log_level& reporting_level(){ | |||
std::call_once(once, [](){ init_logging();}); | |||
return logging::Log<logging::Output2FILE>::reporting_level(); | |||
} | |||
}; | |||
} | |||
#undef LOG | |||
#define LOG(level) \ | |||
if (level > FILELOG_MAX_LEVEL) ;\ | |||
else if (level > logging::Logger::reporting_level() || !logging::Output2FILE::stream()) ; \ | |||
else sysc::Logger().get(level) | |||
#endif /* _SYSC_REPORT_H_ */ |
@ -0,0 +1,204 @@ | |||
/******************************************************************************* | |||
* Copyright (C) 2017, MINRES Technologies GmbH | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright notice, | |||
* this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright notice, | |||
* this list of conditions and the following disclaimer in the documentation | |||
* and/or other materials provided with the distribution. | |||
* | |||
* 3. Neither the name of the copyright holder nor the names of its contributors | |||
* may be used to endorse or promote products derived from this software | |||
* without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
* POSSIBILITY OF SUCH DAMAGE. | |||
* | |||
* Contributors: | |||
* eyck@minres.com - initial API and implementation | |||
******************************************************************************/ | |||
#ifndef _UTIL_LOGGING_H_ | |||
#define _UTIL_LOGGING_H_ | |||
#include <sstream> | |||
#include <string> | |||
#include <vector> | |||
#include <iterator> | |||
#include <cstring> | |||
#include <mutex> | |||
#include <stdio.h> | |||
#include <sys/time.h> | |||
#define LEVELS(FOO) FOO(none) FOO(fatal) FOO(error) FOO(warning) FOO(info) FOO(debug) FOO(trace) | |||
#define DO_DESCRIPTION(e) #e, | |||
#define DO_ENUM(e) e, | |||
namespace logging { | |||
static const char * const buffer[] = { LEVELS(DO_DESCRIPTION)}; | |||
enum log_level { LEVELS(DO_ENUM) }; | |||
inline std::string now_time(); | |||
template <typename T> | |||
class Log{ | |||
public: | |||
Log(){}; | |||
virtual ~Log(){ | |||
os << std::endl; | |||
T::output(os.str()); | |||
//TODO: use a more specific exception | |||
if(get_last_log_level() == fatal) throw std::exception(); | |||
}; | |||
std::ostringstream& get(log_level level = info){ | |||
os << "- " << now_time(); | |||
os << " " << to_string(level) << ": "; | |||
get_last_log_level()=level; | |||
return os; | |||
}; | |||
public: | |||
static log_level& reporting_level(){ | |||
static log_level reportingLevel = warning; | |||
return reportingLevel; | |||
} | |||
static std::string to_string(log_level level){ | |||
return std::string(get_log_level_cstr()[level]); | |||
}; | |||
static log_level from_string(const std::string& level) { | |||
for(unsigned int i=none; i<=trace; i++) | |||
if(!strncasecmp(level.c_str(), (const char*)(get_log_level_cstr()+i), strlen((const char*)get_log_level_cstr()+i))) return i; | |||
Log<T>().Get(warning) << "Unknown logging level '" << level << "'. Using INFO level as default."; | |||
return info; | |||
} | |||
protected: | |||
log_level& get_last_log_level(){ | |||
static log_level level = trace; | |||
return level; | |||
} | |||
static const char* const * get_log_level_cstr(){ | |||
return buffer; | |||
}; | |||
std::ostringstream os; | |||
private: | |||
Log(const Log&); | |||
Log& operator =(const Log&); | |||
}; | |||
struct Output2FILE { | |||
static FILE*& stream(){ | |||
static FILE* pStream = stderr; | |||
return pStream; | |||
} | |||
static void output(const std::string& msg){ | |||
static std::mutex mtx; | |||
std::lock_guard<std::mutex> lock(mtx); | |||
FILE* pStream = stream(); | |||
if (!pStream) return; | |||
fprintf(pStream, "%s", msg.c_str()); | |||
fflush(pStream); | |||
} | |||
}; | |||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) | |||
# if defined (BUILDING_FILELOG_DLL) | |||
# define FILELOG_DECLSPEC __declspec (dllexport) | |||
# elif defined (USING_FILELOG_DLL) | |||
# define FILELOG_DECLSPEC __declspec (dllimport) | |||
# else | |||
# define FILELOG_DECLSPEC | |||
# endif // BUILDING_DBSIMPLE_DLL | |||
#else | |||
# define FILELOG_DECLSPEC | |||
#endif // _WIN32 | |||
class FILELOG_DECLSPEC Logger : public Log<Output2FILE> {}; | |||
//typedef Log<Output2FILE> Logger; | |||
#ifndef FILELOG_MAX_LEVEL | |||
#define FILELOG_MAX_LEVEL logging::trace | |||
#endif | |||
#define LOG(level) \ | |||
if (level > FILELOG_MAX_LEVEL) ;\ | |||
else if (level > logging::Logger::reporting_level() || !logging::Output2FILE::stream()) ; \ | |||
else logging::Logger().get(level) | |||
#if defined(WIN32) | |||
#include <windows.h> | |||
inline std::string now_time(){ | |||
const int MAX_LEN = 200; | |||
char buffer[MAX_LEN]; | |||
if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, "HH':'mm':'ss", buffer, MAX_LEN) == 0) | |||
return "Error in now_time()"; | |||
char result[100] = {0}; | |||
static DWORD first = GetTickCount(); | |||
std::sprintf(result, "%s.%03ld", buffer, (long)(GetTickCount() - first) % 1000); | |||
return result; | |||
} | |||
#else | |||
inline std::string now_time(){ | |||
char buffer[11]; | |||
time_t t; | |||
time(&t); | |||
tm r = {0}; | |||
strftime(buffer, sizeof(buffer), "%X", localtime_r(&t, &r)); | |||
struct timeval tv; | |||
gettimeofday(&tv, 0); | |||
char result[100] = {0}; | |||
sprintf(result, "%s.%03ld", buffer, (long)tv.tv_usec / 1000); | |||
return result; | |||
} | |||
#endif //WIN32 | |||
// a print function for a vector | |||
template<typename T> | |||
std::ostream& operator<< (std::ostream& stream, const std::vector<T>& vector) { | |||
copy(vector.begin(), vector.end(), std::ostream_iterator<T>(stream, ",")); | |||
return stream; | |||
} | |||
} // namespace | |||
#undef LEVELS | |||
#undef CAT | |||
#ifndef NDEBUG | |||
# define ASSERT(condition, message) \ | |||
do { \ | |||
if (! (condition)) { \ | |||
logging::Logger().Get(logging::fatal) << "Assertion `" #condition "` failed in " << __FILE__ << " line " << __LINE__ << ": " << message << std::endl; \ | |||
std::terminate(); \ | |||
} \ | |||
} while (false) | |||
#else | |||
# define ASSERT(condition, message) do { } while (false) | |||
#endif | |||
#define CHECK(condition, message) \ | |||
do { \ | |||
if (! (condition)) { \ | |||
logging::Logger().Get(logging::fatal) << "Check of `" #condition "` failed in " << __FILE__ << " line " << __LINE__ << ": " << message << std::endl; \ | |||
std::terminate(); \ | |||
} \ | |||
} while (false) | |||
#endif /* _UTIL_LOGGING_H_ */ |
@ -0,0 +1,72 @@ | |||
/* | |||
* report.cpp | |||
* | |||
* Created on: 19.09.2017 | |||
* Author: ubuntu | |||
*/ | |||
#include <sysc/report.h> | |||
#include <sr_report/sr_report.h> | |||
using namespace sc_core; | |||
static const std::string compose_message(const sc_report& rep){ | |||
std::stringstream os; | |||
sr_report *srr = dynamic_cast<sr_report *>(const_cast<sc_report *>(&rep)); | |||
if(srr) { | |||
for(std::vector<v::pair>::const_iterator iter = srr->pairs.begin(); iter!=srr->pairs.end(); iter++) { | |||
os << '['<<iter->name << ':'; | |||
switch(iter->type) { | |||
case v::pair::INT32: os << std::hex << std::setfill('0') << "0x" << std::setw(8) << boost::any_cast<int32_t>(iter->data); break; | |||
case v::pair::UINT32: os << std::hex << std::setfill('0') << "0x" << std::setw(8) << boost::any_cast<uint32_t>(iter->data); break; | |||
case v::pair::INT64: os << std::hex << std::setfill('0') << "0x" << std::setw(16) << boost::any_cast<int64_t>(iter->data); break; | |||
case v::pair::UINT64: os << std::hex << std::setfill('0') << "0x" << std::setw(16) << boost::any_cast<uint64_t>(iter->data); break; | |||
case v::pair::STRING: os << boost::any_cast<std::string>(iter->data).c_str(); break; | |||
case v::pair::BOOL: os << (boost::any_cast<bool>(iter->data)? "true" : "false"); break; | |||
case v::pair::DOUBLE: os << boost::any_cast<double>(iter->data); break; | |||
case v::pair::TIME: os << boost::any_cast<sc_core::sc_time>(iter->data).to_string(); break; | |||
default: os << boost::any_cast<int32_t>(iter->data); | |||
} | |||
os << ']'; | |||
} | |||
os<<' '; | |||
} | |||
if ( rep.get_id() >= 0 ) | |||
os << "("<< "IWEF"[rep.get_severity()] << rep.get_id() << ") "; | |||
os << rep.get_msg_type(); | |||
if( *rep.get_msg() ) | |||
os << ": " << rep.get_msg(); | |||
if( rep.get_severity() > SC_INFO ){ | |||
char line_number_str[16]; | |||
os << "(file: " << rep.get_file_name() << ":" << rep.get_line_number()<<")"; | |||
sc_simcontext* simc = sc_get_curr_simcontext(); | |||
if( simc && sc_is_running() ){ | |||
const char* proc_name = rep.get_process_name(); | |||
if( proc_name ) | |||
os << "(process: " << proc_name << " @ " << rep.get_time().to_string()<<")"; | |||
} | |||
} | |||
return os.str(); | |||
} | |||
static void report_handler(const sc_report& rep, const sc_actions& actions){ | |||
const logging::log_level map[] = {logging::info, logging::warning, logging::error, logging::fatal}; | |||
if ( actions & SC_DISPLAY ) | |||
LOG(map[rep.get_severity()]) << compose_message(rep); | |||
// if ( (actions & SC_LOG) && log_file_name ) { | |||
// if ( !log_stream ) log_stream = new ::std::ofstream(log_file_name); // ios::trunc | |||
// *log_stream << rep.get_time() << ": " << my_report_compose_message(rep) << ::std::endl; | |||
// } | |||
if ( actions & SC_STOP ) | |||
sc_stop(); | |||
if ( actions & SC_ABORT ) | |||
abort(); | |||
if ( actions & SC_THROW ) | |||
throw rep; | |||
} | |||
void sysc::init_logging(){ | |||
sc_report_handler::set_handler(report_handler); | |||
} | |||
std::once_flag sysc::Logger::once; |