From ff6d8a87f9569a42c7827428f2329280c9b633b9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 1 Aug 2016 01:16:15 -0400 Subject: Implement LV2 log extension as host Only print color logs if output is a terminal. --- src/Configuration.cpp | 1 + src/Log.cpp | 157 +++++++++++++++++++++++++++++++++++++---------- src/URIs.cpp | 1 + src/World.cpp | 6 +- src/server/UndoStack.cpp | 1 - 5 files changed, 132 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 0f3e3d53..7df565be 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -65,6 +65,7 @@ Configuration::Configuration(Forge& forge) add("path", "path", 'L', "Target path for loaded graph", SESSION, forge.String, Atom()); add("queueSize", "queue-size", 'q', "Event queue size", GLOBAL, forge.Int, forge.make(4096)); add("flushLog", "flush-log", 'f', "Flush logs after every entry", SESSION, forge.Bool, forge.make(false)); + add("trace", "trace", 't', "Show LV2 plugin trace messages", SESSION, forge.Bool, forge.make(false)); add("humanNames", "human-names", 0, "Show human names in GUI", GUI, forge.Bool, forge.make(true)); add("portLabels", "port-labels", 0, "Show port labels in GUI", GUI, forge.Bool, forge.make(true)); add("graphDirectory", "graph-directory", 0, "Default directory for opening graphs", GUI, forge.String, Atom()); diff --git a/src/Log.cpp b/src/Log.cpp index c72f3dbb..b2d30b7d 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -14,65 +14,160 @@ along with Ingen. If not, see . */ -#include +#include #include "ingen/Log.hpp" +#include "ingen/Node.hpp" #include "ingen/URIs.hpp" +#include "ingen/World.hpp" + +#ifdef HAVE_ISATTY +# include +#else +inline int isatty(int fd) { return 0; } +#endif namespace Ingen { -static const char* const ANSI_RESET = "\033[0m"; -static const char* const ANSI_RED = "\033[0;31m"; -//static const char* const ANSI_GREEN = "\033[0;32m"; -static const char* const ANSI_YELLOW = "\033[0;33m"; -//static const char* const ANSI_BLUE = "\033[0;34m"; -//static const char* const ANSI_MAGENTA = "\033[0;35m"; -//static const char* const ANSI_CYAN = "\033[0;36m"; -//static const char* const ANSI_WHITE = "\033[0;37m"; +class ColorContext { +public: + enum class Color { RED = 31, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; + + ColorContext(FILE* stream, Color color) : stream(stream) { + if (isatty(fileno(stream))) { + fprintf(stream, "\033[0;%dm", color); + } + } + + ~ColorContext() { + if (isatty(fileno(stream))) { + fprintf(stream, "\033[0m"); + fflush(stream); + } + } + + + FILE* stream; +}; Log::Log(LV2_Log_Log* log, URIs& uris) : _log(log) , _uris(uris) , _flush(false) + , _trace(false) {} void Log::error(const std::string& msg) { - if (_log) { - _log->printf(_log->handle, _uris.log_Error, "%s", msg.c_str()); - } else { - std::cerr << ANSI_RED << msg << ANSI_RESET; - if (_flush) { - std::flush(std::cerr); - } - } + va_list args; + vtprintf(_uris.log_Error, msg.c_str(), args); } void Log::warn(const std::string& msg) { - if (_log) { - _log->printf(_log->handle, _uris.log_Warning, "%s", msg.c_str()); - } else { - std::cerr << ANSI_YELLOW << msg << ANSI_RESET; - if (_flush) { - std::flush(std::cerr); - } - } + va_list args; + vtprintf(_uris.log_Warning, msg.c_str(), args); } void Log::info(const std::string& msg) { + va_list args; + vtprintf(_uris.log_Note, msg.c_str(), args); +} + +void +Log::trace(const std::string& msg) +{ + va_list args; + vtprintf(_uris.log_Trace, msg.c_str(), args); +} + +void +Log::print(FILE* stream, const std::string& msg) +{ + fprintf(stream, "%s", msg.c_str()); + if (_flush) { + fflush(stdout); + } +} + +int +Log::vtprintf(LV2_URID type, const char* fmt, va_list args) +{ + int ret = 0; if (_log) { - _log->printf(_log->handle, _uris.log_Note, "%s", msg.c_str()); + ret = _log->vprintf(_log->handle, type, fmt, args); + } else if (type == _uris.log_Error) { + ColorContext ctx(stderr, ColorContext::Color::RED); + ret = vfprintf(stderr, fmt, args); + } else if (type == _uris.log_Warning) { + ColorContext ctx(stderr, ColorContext::Color::YELLOW); + ret = vfprintf(stderr, fmt, args); + } else if (type == _uris.log_Note) { + ColorContext ctx(stderr, ColorContext::Color::GREEN); + ret = vfprintf(stdout, fmt, args); + } else if (_trace && type == _uris.log_Trace) { + ColorContext ctx(stderr, ColorContext::Color::GREEN); + ret = vfprintf(stderr, fmt, args); } else { - std::cout << msg; - if (_flush) { - std::flush(std::cout); - } + fprintf(stderr, "Unknown log type %d\n", type); + return 0; } + if (_flush) { + fflush(stdout); + } + return ret; +} + +static int +log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list args) +{ + Log::Feature::Handle* f = (Log::Feature::Handle*)handle; + va_list noargs; + + int ret = f->log->vtprintf(type, f->node->path().c_str(), noargs); + ret += f->log->vtprintf(type, ": ", noargs); + ret += f->log->vtprintf(type, fmt, args); + + return ret; +} + +static int +log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + const int ret = log_vprintf(handle, type, fmt, args); + va_end(args); + + return ret; +} + +static void +free_log_feature(LV2_Feature* feature) { + LV2_Log_Log* lv2_log = (LV2_Log_Log*)feature->data; + free(lv2_log->handle); + free(feature); +} + +SPtr +Log::Feature::feature(World* world, Node* block) +{ + Handle* handle = (Handle*)calloc(1, sizeof(Handle)); + handle->lv2_log.handle = handle; + handle->lv2_log.printf = log_printf; + handle->lv2_log.vprintf = log_vprintf; + handle->log = &world->log(); + handle->node = block; + + LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature)); + f->URI = LV2_LOG__log; + f->data = &handle->lv2_log; + + return SPtr(f, &free_log_feature); } } // namespace Ingen diff --git a/src/URIs.cpp b/src/URIs.cpp index 005490c4..b272e48e 100644 --- a/src/URIs.cpp +++ b/src/URIs.cpp @@ -110,6 +110,7 @@ URIs::URIs(Forge& f, URIMap* map, LilvWorld* lworld) , ingen_value (forge, map, lworld, INGEN__value) , log_Error (forge, map, lworld, LV2_LOG__Error) , log_Note (forge, map, lworld, LV2_LOG__Note) + , log_Trace (forge, map, lworld, LV2_LOG__Trace) , log_Warning (forge, map, lworld, LV2_LOG__Warning) , lv2_AudioPort (forge, map, lworld, LV2_CORE__AudioPort) , lv2_CVPort (forge, map, lworld, LV2_CORE__CVPort) diff --git a/src/World.cpp b/src/World.cpp index 105363b6..38b27a9a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -111,8 +111,8 @@ public: , uri_map(new URIMap(log, map, unmap)) , forge(new Forge(*uri_map)) , uris(new URIs(*forge, uri_map, lilv_world)) - , log(lv2_log, *uris) , conf(*forge) + , log(lv2_log, *uris) { // Parse default configuration files std::list files = conf.load_default("ingen", "options.ttl"); @@ -123,12 +123,14 @@ public: // Parse command line options, overriding configuration file values conf.parse(argc, argv); log.set_flush(conf.option("flush-log").get()); + log.set_trace(conf.option("trace").get()); lv2_features = new LV2Features(); lv2_features->add_feature(uri_map->urid_map_feature()); lv2_features->add_feature(uri_map->urid_unmap_feature()); lv2_features->add_feature(SPtr(new InstanceAccess())); lv2_features->add_feature(SPtr(new DataAccess())); + lv2_features->add_feature(SPtr(new Log::Feature())); lilv_world_load_all(lilv_world); // Set up RDF namespaces @@ -215,8 +217,8 @@ public: Forge* forge; URIs* uris; LV2_Log_Log* lv2_log; - Log log; Configuration conf; + Log log; SPtr interface; SPtr engine; SPtr serialiser; diff --git a/src/server/UndoStack.cpp b/src/server/UndoStack.cpp index f8a7f37b..77d26871 100644 --- a/src/server/UndoStack.cpp +++ b/src/server/UndoStack.cpp @@ -15,7 +15,6 @@ */ #include -#include #include "ingen/URIMap.hpp" #include "ingen/URIs.hpp" -- cgit v1.2.1