diff --git a/AUTHORS.md b/AUTHORS.md index 95563bce7..ebba1681f 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,60 +2,60 @@ Mapnik is written by Artem Pavlenko with contributions from: -Andy Allen -AJ Ashton -Matt Amos -Lucio Asnaghi -Justin Bronn -Christopher Brown -Jon Burgess -Toby Collet -Robert Coup -Berteun Damman -Craig de Stigter -Jean-Francois Doyon -David Eastcott -Krzysztof Godlewski -Beau Gunderson -John Hague -Dominic Hargreaves -Aubrey Holland -Tom Hughes -Konstantin Käfer -Mak Kolybabi -Peter Körner -Hermann Kraus -Stella Laurenzo -David Leaver -Carlos López -Dennis Luxen -Tom MacWright -Michal Migurski -Andrii Mishkovskyi -Ben Moores -Dražen Odobašić -Cameron Patrick -Igor Podolskiy -Reid Priedhorsky -Brian Quinion -Marcin Rudowski -Christopher Schmidt -Andreas Schneider -Vincent Schut -Ehud Shabtai -David Siegel -Steve Singer -Paul Smith -Vince Spader -Philipp Spitzer -Dane Springmeyer -Dave Stubbs -River Tarnell -Oliver Tonnhofer -Alberto Valverde -Martijn van Oosterhout -Andreas Volz -Lennard voor den Dag -Shaun Walbridge -Nick Whitelegg -Leslie Wu +* Andy Allen +* AJ Ashton +* Matt Amos +* Lucio Asnaghi +* Justin Bronn +* Christopher Brown +* Jon Burgess +* Toby Collet +* Robert Coup +* Berteun Damman +* Craig de Stigter +* Jean-Francois Doyon +* David Eastcott +* Krzysztof Godlewski +* Beau Gunderson +* John Hague +* Dominic Hargreaves +* Aubrey Holland +* Tom Hughes +* Konstantin Käfer +* Mak Kolybabi +* Peter Körner +* Hermann Kraus +* Stella Laurenzo +* David Leaver +* Carlos López +* Dennis Luxen +* Tom MacWright +* Michal Migurski +* Andrii Mishkovskyi +* Ben Moores +* Dražen Odobašić +* Cameron Patrick +* Igor Podolskiy +* Reid Priedhorsky +* Brian Quinion +* Marcin Rudowski +* Christopher Schmidt +* Andreas Schneider +* Vincent Schut +* Ehud Shabtai +* David Siegel +* Steve Singer +* Paul Smith +* Vince Spader +* Philipp Spitzer +* Dane Springmeyer +* Dave Stubbs +* River Tarnell +* Oliver Tonnhofer +* Alberto Valverde +* Martijn van Oosterhout +* Andreas Volz +* Lennard voor den Dag +* Shaun Walbridge +* Nick Whitelegg +* Leslie Wu diff --git a/CHANGELOG.md b/CHANGELOG.md index 19b01ad12..1ab3c2306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ For a complete change history, see the SVN log. ## Mapnik 2.1.0 +- Improved logging/debugging system with release logs and file redirection (#937 and partially #986, #467) + - GDAL: allow setting nodata value on the fly (will override value if nodata is set in data) (#1161) - GDAL: respect nodata for paletted/colormapped images (#1160) diff --git a/SConstruct b/SConstruct index 30930b7f8..1f906e044 100644 --- a/SConstruct +++ b/SConstruct @@ -347,7 +347,7 @@ opts.AddVariables( # Variables for logging and statistics BoolVariable('ENABLE_LOG', 'Enable logging, which is enabled by default when building in *debug*', 'False'), BoolVariable('ENABLE_STATS', 'Enable global statistics during map processing', 'False'), - ('LOG_FORMAT_STRING', 'The format string used before log output string, piped through strftime (max length of 255 characters)', 'Mapnik LOG> %Y-%m-%d %H:%M:%S:'), + ('DEFAULT_LOG_SEVERITY', 'The default severity of the logger (eg. "info", "debug", "warn", "error", "fatal", "none")', 'error'), # Other variables BoolVariable('SHAPE_MEMORY_MAPPED_FILE', 'Utilize memory-mapped files in Shapefile Plugin (higher memory usage, better performance)', 'True'), @@ -1417,7 +1417,20 @@ if not preconfigured: ndebug_flags = '-DNDEBUG' # Enable logging in debug mode (always) and release mode (when specified) - log_enabled = ' -DMAPNIK_LOG -DMAPNIK_LOG_FORMAT="%s"' % env['LOG_FORMAT_STRING'] + if env['DEFAULT_LOG_SEVERITY']: + severities = ['info', 'debug', 'warn', 'error', 'fatal', 'none'] + if env['DEFAULT_LOG_SEVERITY'] not in severities: + color_print(1,"Cannot set default logger severity to '%s', available options are 'info', 'debug', 'warn', 'error', 'fatal', 'none'." % env['DEFAULT_LOG_SEVERITY']) + Exit(1) + else: + log_severity = severities.index(env['DEFAULT_LOG_SEVERITY']) + else: + if env['DEBUG']: + log_severity = 1 # debug + else: + log_severity = 3 # error + + log_enabled = ' -DMAPNIK_LOG -DMAPNIK_DEFAULT_LOG_SEVERITY=%d' % log_severity if env['DEBUG']: debug_flags += log_enabled @@ -1432,7 +1445,7 @@ if not preconfigured: # Add rdynamic to allow using statics between application and plugins # http://stackoverflow.com/questions/8623657/multiple-instances-of-singleton-across-shared-libraries-on-linux - if env['PLATFORM'] != 'Darwin': + if env['PLATFORM'] != 'Darwin' and env['CXX'] == 'g++': env.MergeFlags('-rdynamic') # Customizing the C++ compiler flags depending on: @@ -1719,7 +1732,7 @@ if not HELP_REQUESTED: # devtools not ready for public #SConscript('utils/ogrindex/build.py') - #SConscript('utils/svg2png/build.py') + SConscript('utils/svg2png/build.py') env['LIBS'].remove('boost_program_options%s' % env['BOOST_APPEND']) else : color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' won't be available") diff --git a/bindings/python/mapnik_logger.cpp b/bindings/python/mapnik_logger.cpp index b6c0aeba9..7ce25227a 100644 --- a/bindings/python/mapnik_logger.cpp +++ b/bindings/python/mapnik_logger.cpp @@ -22,112 +22,48 @@ #include #include - -using mapnik::logger::severity; -using mapnik::logger::format; -using mapnik::logger::output; - -void set_severity(const severity::type& s) -{ - severity::set(s); -} - -severity::type get_severity() -{ - return severity::get(); -} - -void set_object_severity(const std::string& object_name, const severity::type& s) -{ - severity::set_object(object_name, s); -} - -severity::type get_object_severity(const std::string& object_name) -{ - return severity::get_object(object_name); -} - +#include void export_logger() { - using namespace boost::python; - - enum_("SeverityType") - .value("Info", severity::info) - .value("Debug", severity::debug) - .value("Warn", severity::warn) - .value("Error", severity::error) - .value("Fatal", severity::fatal) - .value("None", severity::none) - ; - -/* + using mapnik::logger; using mapnik::singleton; using mapnik::CreateStatic; using namespace boost::python; - class_,boost::noncopyable>("Singleton",no_init) - .def("instance",&singleton::instance, + class_,boost::noncopyable>("Singleton",no_init) + .def("instance",&singleton::instance, return_value_policy()) .staticmethod("instance") ; - class_ >, - boost::noncopyable>("Severity",no_init) - .def("get",&severity::get) - .def("set",&severity::set) - .def("get_object",&severity::get_object) - .def("set_object",&severity::set_object) - .staticmethod("get") - .staticmethod("set") - .staticmethod("get_object") - .staticmethod("set_object") + class_ >, + boost::noncopyable>("logger",no_init) + .def_readonly("Info", logger::info) + .def_readonly("Debug", logger::debug) + .def_readonly("Warn", logger::warn) + .def_readonly("Error", logger::error) + .def_readonly("Fatal", logger::fatal) + .def_readonly("None", logger::none) + .def("get_severity", &logger::get_severity) + .def("set_severity", &logger::set_severity) + .def("get_object_severity", &logger::get_object_severity) + .def("set_object_severity", &logger::set_object_severity) + .def("clear_object_severity", &logger::clear_object_severity) + .def("get_format", &logger::get_format) + .def("set_format", &logger::set_format) + .def("str", &logger::str) + .def("use_file", &logger::use_file) + .def("use_console", &logger::use_console) + .staticmethod("get_severity") + .staticmethod("set_severity") + .staticmethod("get_object_severity") + .staticmethod("set_object_severity") + .staticmethod("clear_object_severity") + .staticmethod("get_format") + .staticmethod("set_format") + .staticmethod("str") + .staticmethod("use_file") + .staticmethod("use_console") ; -*/ - - def("set_severity", &set_severity, - "\n" - "Set global logger severity.\n" - "\n" - "Usage:\n" - ">>> from mapnik import SeverityType, set_severity\n" - ">>> set_severity(SeverityType.None)\n" - ">>> set_severity(SeverityType.Info)\n" - ">>> set_severity(SeverityType.Debug)\n" - ">>> set_severity(SeverityType.Warn)\n" - ">>> set_severity(SeverityType.Error)\n" - ">>> set_severity(SeverityType.Fatal)\n" - ); - - def("get_severity", &get_severity, - "\n" - "Get global logger severity.\n" - "\n" - "Usage:\n" - ">>> from mapnik import get_severity\n" - ">>> get_severity()\n" - ); - - def("set_object_severity", &set_object_severity, - "\n" - "Set logger severity for a single object.\n" - "\n" - "Usage:\n" - ">>> from mapnik import SeverityType, set_object_severity\n" - ">>> set_object_severity('ogr', SeverityType.None)\n" - ">>> set_object_severity('gdal', SeverityType.Info)\n" - ">>> set_object_severity('cairo_renderer', SeverityType.Debug)\n" - ">>> set_object_severity('agg_renderer', SeverityType.Warn)\n" - ">>> set_object_severity('bindings', SeverityType.Error)\n" - ); - - def("get_object_severity", &get_object_severity, - "\n" - "Get logger severity for a single object.\n" - "\n" - "Usage:\n" - ">>> from mapnik import get_object_severity" - ">>> get_object_severity('ogr')\n" - ); - } diff --git a/include/mapnik/debug.hpp b/include/mapnik/debug.hpp index 93ff737d0..67e9007c5 100644 --- a/include/mapnik/debug.hpp +++ b/include/mapnik/debug.hpp @@ -43,122 +43,115 @@ namespace mapnik { - namespace logger { - class MAPNIK_DECL severity : - public singleton, - private boost::noncopyable + class MAPNIK_DECL logger : + public singleton, + private boost::noncopyable + { + public: + enum severity_type { - public: - enum type - { - info, - debug, - warn, - error, - fatal, - none - }; + info, + debug, + warn, + error, + fatal, + none + }; - typedef boost::unordered_map severity_map; + typedef boost::unordered_map severity_map; - // globally get security level - static type get() + // global security level + static severity_type get_severity() + { + return severity_level_; + } + + static void set_severity(const severity_type& severity_level) + { +#ifdef MAPNIK_THREADSAFE + boost::mutex::scoped_lock lock(severity_mutex_); +#endif + + severity_level_ = severity_level; + } + + // per object security levels + static severity_type get_object_severity(const std::string& object_name) + { + severity_map::iterator it = object_severity_level_.find(object_name); + if (object_name.empty() || it == object_severity_level_.end()) { return severity_level_; } - - // globally set security level - static void set(const type& severity_level) + else { -#ifdef MAPNIK_THREADSAFE - boost::mutex::scoped_lock lock(mutex_); -#endif - - severity_level_ = severity_level; + return it->second; } + } - // per object get security level - static type get_object(const std::string& object_name) - { - severity_map::iterator it = object_severity_level_.find(object_name); - if (object_name.empty() || it == object_severity_level_.end()) - { - return severity_level_; - } - else - { - return it->second; - } - } - - // per object set security level - static void set_object(const std::string& object_name, - const type& security_level) - { -#ifdef MAPNIK_THREADSAFE - boost::mutex::scoped_lock lock(mutex_); -#endif - if (! object_name.empty()) - { - object_severity_level_[object_name] = security_level; - } - } - - private: - static type severity_level_; - static severity_map object_severity_level_; - -#ifdef MAPNIK_THREADSAFE - static boost::mutex mutex_; -#endif - }; - - - class MAPNIK_DECL format : - public singleton, - private boost::noncopyable + static void set_object_severity(const std::string& object_name, + const severity_type& security_level) { - public: - - static std::string get() - { - return format_; - } - - static void set(const std::string& format) - { #ifdef MAPNIK_THREADSAFE - boost::mutex::scoped_lock lock(mutex_); + boost::mutex::scoped_lock lock(severity_mutex_); #endif - format_ = format; + if (! object_name.empty()) + { + object_severity_level_[object_name] = security_level; } + } - static std::string str(); - - private: - static std::string format_; - -#ifdef MAPNIK_THREADSAFE - static boost::mutex mutex_; -#endif - }; - - - class MAPNIK_DECL output : - public singleton, - private boost::noncopyable + static void clear_object_severity() { - public: - static void use_file(const std::string& filepath); - static void use_console(); +#ifdef MAPNIK_THREADSAFE + boost::mutex::scoped_lock lock(severity_mutex_); +#endif - private: - static std::ofstream file_output_; - static std::string file_name_; - static std::streambuf* saved_buf_; - }; + object_severity_level_.clear(); + } + // format + static std::string get_format() + { + return format_; + } + + static void set_format(const std::string& format) + { +#ifdef MAPNIK_THREADSAFE + boost::mutex::scoped_lock lock(format_mutex_); +#endif + format_ = format; + } + + // interpolate the format string for output + static std::string str(); + + // output + static void use_file(const std::string& filepath); + static void use_console(); + + private: + static severity_type severity_level_; + static severity_map object_severity_level_; + static bool severity_env_check_; + + static std::string format_; + static bool format_env_check_; + + static std::ofstream file_output_; + static std::string file_name_; + static std::streambuf* saved_buf_; + +#ifdef MAPNIK_THREADSAFE + static boost::mutex severity_mutex_; + static boost::mutex format_mutex_; +#endif + }; + + + namespace detail { template class clog_sink @@ -166,19 +159,19 @@ namespace mapnik { public: typedef std::basic_ostringstream stream_buffer; - void operator()(const stream_buffer &s) + void operator()(const logger::severity_type& severity, const stream_buffer &s) { #ifdef MAPNIK_THREADSAFE static boost::mutex mutex; boost::mutex::scoped_lock lock(mutex); #endif - std::clog << format::str() << " " << s.str() << std::endl; + std::clog << logger::str() << " " << s.str() << std::endl; } }; template