From a1cb3b614b8c48bfa66cb9e15416cf4658693a69 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 20 Jul 2021 02:48:12 +0200 Subject: [PATCH] Add a +editor flag to YABRIDGE_DEBUG_LEVEL --- CHANGELOG.md | 4 ++ README.md | 6 ++- src/common/logging/common.cpp | 72 ++++++++++++++++++++--------------- src/common/logging/common.h | 32 +++++++++++++++- 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b497df4..1e97dcbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ Versioning](https://semver.org/spec/v2.0.0.html). shared memory for processing audio in plugins with a lot of inputs or outputs. - Also added a warning for thisq in the initialization message if yabridge detects a low value for `RLIMIT_MEMLOCK`. +- Added a `+editor` flag to the `YABRIDGE_DEBUG_LEVEL` environment variable that + can be combined with any debug level to also print debug tracing information + about the plugin editor window. This can be useful for diagnosing DAW or + window manager specific issues. ### Fixed diff --git a/README.md b/README.md index 0123aa05..f5e45d6b 100644 --- a/README.md +++ b/README.md @@ -784,8 +784,10 @@ offers these two environment variables to control yabridge's logging facilities: `env YABRIDGE_DEBUG_FILE=/tmp/yabridge.log `, and then use `tail -F /tmp/yabridge.log` to keep track of the output. If this option is not present then yabridge will write all of its debug output to STDERR instead. -- `YABRIDGE_DEBUG_LEVEL={0,1,2}` allows you to set the verbosity of the debug - information. Each level increases the amount of debug information printed: +- `YABRIDGE_DEBUG_LEVEL={0,1,2}{,+editor}` allows you to set the verbosity of + the debug information. You can set a debug level, optionally followed by + `+editor` to also get more debug output related to the editor window handling. + Each level increases the amount of debug information printed: - A value of `0` (the default) means that yabridge will only log the output from the Wine process and some basic information about the diff --git a/src/common/logging/common.cpp b/src/common/logging/common.cpp index 111ad6b8..7b4f9f9f 100644 --- a/src/common/logging/common.cpp +++ b/src/common/logging/common.cpp @@ -41,21 +41,39 @@ constexpr char logging_file_environment_variable[] = "YABRIDGE_DEBUG_FILE"; constexpr char logging_verbosity_environment_variable[] = "YABRIDGE_DEBUG_LEVEL"; +/** + * The `YABRIDGE_DEBUG_LEVEL` flag for enabling editor tracing. + */ +constexpr char editor_tracing_flag[] = "+editor"; + Logger::Logger(std::shared_ptr stream, Verbosity verbosity_level, + bool editor_tracing, std::string prefix, bool prefix_timestamp) : verbosity(verbosity_level), + editor_tracing(editor_tracing), stream(stream), prefix(prefix), prefix_timestamp(prefix_timestamp) {} -Logger Logger::create_from_environment(std::string prefix) { +Logger Logger::create_from_environment(std::string prefix, + std::shared_ptr stream) { bp::environment env = boost::this_process::environment(); - std::string file_path = env[logging_file_environment_variable].to_string(); + const std::string file_path = + env[logging_file_environment_variable].to_string(); std::string verbosity = env[logging_verbosity_environment_variable].to_string(); + // Editor debug tracing is an optional flag that can be added to any debug + // level (and technically it will also work fine if it's the only option, + // but you're not supposed to do that ;)) + const bool editor_tracing = verbosity.ends_with(editor_tracing_flag); + if (editor_tracing) { + verbosity = + verbosity.substr(0, verbosity.size() - strlen(editor_tracing_flag)); + } + // Default to `Verbosity::basic` if the environment variable has not // been set or if it is not an integer. Verbosity verbosity_level; @@ -65,41 +83,35 @@ Logger Logger::create_from_environment(std::string prefix) { verbosity_level = Verbosity::basic; } - // If `file` points to a valid location then use create/truncate the - // file and write all of the logs there, otherwise use STDERR - auto log_file = std::make_shared( - file_path, std::fstream::out | std::fstream::app); - if (log_file->is_open()) { - return Logger(log_file, verbosity_level, prefix); - } else { - // For STDERR we sadly can't just use `std::cerr`. In the group process - // we need to capture all output generated by the process itself, and - // the only way to do this is by reopening the STDERR and STDOUT streams - // to a pipe. Luckily `/dev/stderr` stays unaffected, so we can still - // write there without causing infinite loops. - return Logger(std::make_shared( - "/dev/stderr", std::fstream::out | std::fstream::app), - verbosity_level, prefix); + if (!stream) { + // If `file` points to a valid location then use create/truncate the + // file and write all of the logs there, otherwise use STDERR + const auto log_file = std::make_shared( + file_path, std::fstream::out | std::fstream::app); + if (log_file->is_open()) { + stream = log_file; + return Logger(log_file, verbosity_level, editor_tracing, prefix); + } else { + // For STDERR we sadly can't just use `std::cerr`. In the group + // process we need to capture all output generated by the process + // itself, and the only way to do this is by reopening the STDERR + // and STDOUT streams to a pipe. Luckily `/dev/stderr` stays + // unaffected, so we can still write there without causing infinite + // loops. + stream = std::make_shared( + "/dev/stderr", std::fstream::out | std::fstream::app); + } } + + return Logger(stream, verbosity_level, editor_tracing, prefix); } Logger Logger::create_wine_stderr() { - bp::environment env = boost::this_process::environment(); - std::string verbosity = - env[logging_verbosity_environment_variable].to_string(); - - Verbosity verbosity_level; - try { - verbosity_level = static_cast(std::stoi(verbosity)); - } catch (const std::invalid_argument&) { - verbosity_level = Verbosity::basic; - } - // We're logging directly to `std::cerr` instead of to `/dev/stderr` because // we want the STDERR redirection from the group host processes to still // function here - return Logger(std::shared_ptr(&std::cerr, [](auto*) {}), - verbosity_level, "", false); + return create_from_environment( + "", std::shared_ptr(&std::cerr, [](auto*) {})); } void Logger::log(const std::string& message) { diff --git a/src/common/logging/common.h b/src/common/logging/common.h index ea4ec057..a4abbab7 100644 --- a/src/common/logging/common.h +++ b/src/common/logging/common.h @@ -96,6 +96,9 @@ class Logger { * @param verbosity_level The verbosity of the logging, see the * `Logger::Verbosity` constants above for a description of the verbosity * levels. + * @param editor_tracing Whether we should enable debug tracing for the + * editor window handling. If we end up adding more of these options, we + * should move to a bitfield or something. * @param prefix An optional prefix for the logger. Useful for differentiate * messages coming from the Wine VST host. Should end with a single space * character. @@ -107,6 +110,7 @@ class Logger { */ Logger(std::shared_ptr stream, Verbosity verbosity_level, + bool editor_tracing, std::string prefix = "", bool prefix_timestamp = true); @@ -116,8 +120,12 @@ class Logger { * * @param prefix A message to prepend for every log message, useful to * differentiate between the Wine process and the Linux VST plugin. + * @param stream If specified, disregard `YABRIDGE_DEBUG_FILE` and output + * the log to this stream isntead. */ - static Logger create_from_environment(std::string prefix = ""); + static Logger create_from_environment( + std::string prefix = "", + std::shared_ptr stream = nullptr); /** * Create a special logger instance that outputs directly to STDERR without @@ -173,7 +181,21 @@ class Logger { */ template F> void log_trace(F&& fn) { - if (verbosity >= Verbosity::all_events) { + if (verbosity >= Verbosity::all_events) [[unlikely]] { + log(fn()); + } + } + + /** + * Log a message that should only be printed when the `editor_tracing` + * option is enabled. This can be useful to provide debugging information + * for weird setup-specific bugs. + * + * @param message A lambda producing a string that should be written. + */ + template F> + void log_editor_trace(F&& fn) { + if (editor_tracing) [[unlikely]] { log(fn()); } } @@ -184,6 +206,12 @@ class Logger { */ const Verbosity verbosity; + /** + * If this is set to true, then we'll print debug traces for the plugin + * editor. + */ + const bool editor_tracing; + private: /** * The output stream to write the log messages to. Typically either STDERR