summaryrefslogtreecommitdiffstats
path: root/src/debug/logger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/logger.cpp')
-rw-r--r--src/debug/logger.cpp231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/debug/logger.cpp b/src/debug/logger.cpp
new file mode 100644
index 0000000..37b8221
--- /dev/null
+++ b/src/debug/logger.cpp
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape::Debug::Logger - debug logging facility
+ *
+ * Authors:
+ * MenTaLguY <mental@rydia.net>
+ *
+ * Copyright (C) 2005 MenTaLguY
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cstring>
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+#include <glib.h>
+#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 << "&amp;";
+ break;
+ case '"':
+ os << "&quot;";
+ break;
+ case '\'':
+ os << "&apos;";
+ break;
+ case '<':
+ os << "&lt;";
+ break;
+ case '>':
+ os << "&gt;";
+ 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<std::shared_ptr<std::string>> 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<Event::CORE> 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 << "<?xml version=\"1.0\"?>\n";
+ log_stream.flush();
+ _enabled = true;
+ start<SessionEvent>();
+ 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<std::string>(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 << "</" << tag_stack().back()->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 :