// SPDX-License-Identifier: GPL-2.0-or-later /* * Inkscape::Debug::Logger - debug logging facility * * Authors: * MenTaLguY * * Copyright (C) 2005 MenTaLguY * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include #include #include #include #include #include #include "inkscape-version.h" #include "debug/logger.h" #include "debug/simple-event.h" namespace Inkscape { namespace Debug { bool Logger::_enabled=false; bool Logger::_category_mask[Event::N_CATEGORIES]; namespace { static void write_escaped_value(std::ostream &os, char const *value) { for ( char const *current=value ; *current ; ++current ) { switch (*current) { case '&': os << "&"; break; case '"': os << """; break; case '\'': os << "'"; break; case '<': os << "<"; break; case '>': os << ">"; break; default: os.put(*current); } } } static void write_indent(std::ostream &os, unsigned depth) { for ( unsigned i = 0 ; i < depth ; i++ ) { os.write(" ", 2); } } static std::ofstream log_stream; static bool empty_tag=false; typedef std::vector> TagStack; static TagStack &tag_stack() { static TagStack stack; return stack; } static void do_shutdown() { Debug::Logger::shutdown(); } static bool equal_range(char const *c_string, char const *start, char const *end) { return !std::strncmp(start, c_string, end - start) && !c_string[end - start]; } static void set_category_mask(bool * const mask, char const *filter) { if (!filter) { for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) { mask[i] = true; } return; } else { for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) { mask[i] = false; } mask[Event::CORE] = true; } char const *start; char const *end; start = end = filter; while (*end) { while ( *end && *end != ',' ) { end++; } if ( start != end ) { struct CategoryName { char const *name; Event::Category category; }; static const CategoryName category_names[] = { { "CORE", Event::CORE }, { "XML", Event::XML }, { "SPOBJECT", Event::SPOBJECT }, { "DOCUMENT", Event::DOCUMENT }, { "REFCOUNT", Event::REFCOUNT }, { "EXTENSION", Event::EXTENSION }, { "FINALIZERS", Event::FINALIZERS }, { "INTERACTION", Event::INTERACTION }, { "CONFIGURATION", Event::CONFIGURATION }, { "OTHER", Event::OTHER }, { nullptr, Event::OTHER } }; CategoryName const *iter; for ( iter = category_names ; iter->name ; iter++ ) { if (equal_range(iter->name, start, end)) { mask[iter->category] = true; break; } } if (!iter->name) { g_warning("Unknown debugging category %*s", (int)(end - start), start); } } if (*end) { start = end = end + 1; } } } typedef SimpleEvent CoreEvent; class SessionEvent : public CoreEvent { public: SessionEvent() : CoreEvent("session") { _addProperty("inkscape-version", Inkscape::version_string); } }; } void Logger::init() { if (!_enabled) { char const *log_filename=std::getenv("INKSCAPE_DEBUG_LOG"); if (log_filename) { log_stream.open(log_filename); if (log_stream.is_open()) { char const *log_filter=std::getenv("INKSCAPE_DEBUG_FILTER"); set_category_mask(_category_mask, log_filter); log_stream << "\n"; log_stream.flush(); _enabled = true; start(); std::atexit(&do_shutdown); } } } } void Logger::_start(Event const &event) { char const *name=event.name(); if (empty_tag) { log_stream << ">\n"; } write_indent(log_stream, tag_stack().size()); log_stream << "<" << name; unsigned property_count=event.propertyCount(); for ( unsigned i = 0 ; i < property_count ; i++ ) { Event::PropertyPair property=event.property(i); log_stream << " " << property.name << "=\""; write_escaped_value(log_stream, property.value->c_str()); log_stream << "\""; } log_stream.flush(); tag_stack().push_back(std::make_shared(name)); empty_tag = true; event.generateChildEvents(); } void Logger::_skip() { tag_stack().push_back(nullptr); } void Logger::_finish() { if (tag_stack().back()) { if (empty_tag) { log_stream << "/>\n"; } else { write_indent(log_stream, tag_stack().size() - 1); log_stream << "c_str() << ">\n"; } log_stream.flush(); empty_tag = false; } tag_stack().pop_back(); } void Logger::shutdown() { if (_enabled) { while (!tag_stack().empty()) { finish(); } } } } } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :