From 1d2c3d4d7572772db7dc2b0eeec3e8c804f996da Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 6 Mar 2020 15:31:31 +0100 Subject: [PATCH] Add the base for a debug log --- src/common/logging.h | 119 ++++++++++++++++++++++++++++++++ src/plugin/host-bridge.cpp | 5 +- src/plugin/host-bridge.h | 2 + src/wine-host/native-includes.h | 2 + src/wine-host/plugin-bridge.cpp | 1 + src/wine-host/plugin-bridge.h | 3 + 6 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 src/common/logging.h diff --git a/src/common/logging.h b/src/common/logging.h new file mode 100644 index 00000000..8a357a2a --- /dev/null +++ b/src/common/logging.h @@ -0,0 +1,119 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +#include + +/** + * The environment variable indicating whether to log to a file. Will log to + * STDERR if not specified. + */ +constexpr char logging_file_environment_variable[] = "YABRIDGE_DEBUG_FILE"; +/** + * The verbosity of the logging, defaults to `Logger::Verbosity::events` if + * `logging_file_environment_variable` has been set and + * `Logger::Verbosity::basic` otherwise. + * + * @see Logger::Verbosity + */ +constexpr char logging_verbosity_environment_variable[] = + "YABRIDGE_DEBUG_VERBOSITY"; + +/** + * Super basic logging facility meant for debugging malfunctioning VST + * plugins. This is also used to redirect the output of the Wine process + * because DAWs like Bitwig hide this from you, making it hard to debug + * crashing plugins. + */ +class Logger { + public: + enum class Verbosity : int { + /** + * Only output basic information such as the VST plugin that's being + * loaded and Wine's output. Doesn't add timestamps to reduce overhead. + * To quiet down Wine you could optionally also set the `WINEDEBUG` + * environment variable. + */ + basic = 0, + /** + * Also print information about callbacks and functions being called by + * the plugin and the host. Every message is prefixed with a timestamp. + */ + events = 1, + /** + * Also print information about audio buffer processing. This can be + * incredibly verbose and should only be used during development. + */ + verbose = 2 + }; + + /** + * Initialize the logger with the following verbosity level. + * + * @param stream The `std::ostream` instance to use. Typically either a file + * stream or STDERR. + * @param verbosity_level The verbosity of the logging, see the + * `Logger::Verbosity` constants above for a description of the verbosity + * levels. + * @param prefix An optional prefix for the logger. Useful for differentiate + * messages coming from the Wine VST host. + */ + Logger(std::ostream&& stream, + Verbosity verbosity_level, + std::string prefix = "") + : stream(stream), verbosity(verbosity_level), prefix(prefix){}; + + /** + * Create a logger instance based on the set environment variables. + * + * @param prefix A message to prepend for every log message, useful to + * differentiate between the Wine process and the Linus VST plugin. + */ + static Logger create_from_environment(std::string prefix = "") { + auto env = boost::this_process::environment(); + std::string file_path = env.get(logging_file_environment_variable); + std::string verbosity = env.get(logging_verbosity_environment_variable); + + // Default to `Verbosity::basic` if the environment variable has not + // been set or if it is not an integer. + Verbosity verbosity_level; + try { + verbosity_level = static_cast(std::stoi(verbosity)); + } catch (const std::invalid_argument&) { + 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 + std::ofstream log_file(file_path, std::fstream::out); + if (log_file.is_open()) { + return Logger(std::move(log_file), verbosity_level, prefix); + } else { + return Logger(std::move(std::cerr), verbosity_level, prefix); + } + } + + // TODO: Add dedicated logging functions for events and the Wine process's + // STDOUT and STDERR + + private: + std::ostream& stream; + Verbosity verbosity; + std::string prefix; +}; diff --git a/src/plugin/host-bridge.cpp b/src/plugin/host-bridge.cpp index 12d5275b..46400991 100644 --- a/src/plugin/host-bridge.cpp +++ b/src/plugin/host-bridge.cpp @@ -74,9 +74,10 @@ HostBridge::HostBridge(audioMasterCallback host_callback) host_vst_process_replacing(io_context), vst_host_aeffect(io_context), host_callback_function(host_callback), + logger(Logger::create_from_environment()), vst_host(find_wine_vst_host(), - // The Wine VST host needs to know which plugin to load and - // which Unix domain socket to connect to + // The Wine VST host needs to know which plugin to load + // and which Unix domain socket to connect to find_vst_plugin(), socket_endpoint.path(), bp::env = set_wineprefix()), diff --git a/src/plugin/host-bridge.h b/src/plugin/host-bridge.h index 032ab134..ebe665e4 100644 --- a/src/plugin/host-bridge.h +++ b/src/plugin/host-bridge.h @@ -24,6 +24,7 @@ #include #include "../common/communication.h" +#include "../common/logging.h" /** * This handles the communication between the Linux native VST plugin and the @@ -112,6 +113,7 @@ class HostBridge { * The callback function passed by the host to the VST plugin instance. */ audioMasterCallback host_callback_function; + Logger logger; /** * The Wine process hosting the Windows VST plugin. */ diff --git a/src/wine-host/native-includes.h b/src/wine-host/native-includes.h index 26ccddb0..8a2b1a27 100644 --- a/src/wine-host/native-includes.h +++ b/src/wine-host/native-includes.h @@ -39,6 +39,8 @@ #include #include #include +#include +#include #pragma pop_macro("WIN32") #pragma pop_macro("_WIN32") diff --git a/src/wine-host/plugin-bridge.cpp b/src/wine-host/plugin-bridge.cpp index 13a61505..0c2486df 100644 --- a/src/wine-host/plugin-bridge.cpp +++ b/src/wine-host/plugin-bridge.cpp @@ -58,6 +58,7 @@ PluginBridge::PluginBridge(std::string plugin_dll_path, host_vst_parameters(io_context), host_vst_process_replacing(io_context), vst_host_aeffect(io_context), + logger(Logger::create_from_environment("[WINE] ")), process_buffer(std::make_unique()) { // Got to love these C APIs if (plugin_handle == nullptr) { diff --git a/src/wine-host/plugin-bridge.h b/src/wine-host/plugin-bridge.h index 24b61851..91a94e1a 100644 --- a/src/wine-host/plugin-bridge.h +++ b/src/wine-host/plugin-bridge.h @@ -27,6 +27,7 @@ #include #include "../common/communication.h" +#include "../common/logging.h" /** * This handles the communication between the Linux native VST plugin and the @@ -106,6 +107,8 @@ class PluginBridge { */ std::thread process_replacing_handler; + Logger logger; + /** * A scratch buffer for sending and receiving data during `process` and * `processReplacing` calls.