2016-04-04 23:09:18 -05:00
|
|
|
/**
|
|
|
|
|
* @file
|
|
|
|
|
* @brief Source file for ZeroMQ-based Logger class
|
|
|
|
|
* @author Jonathan Thomas <jonathan@openshot.org>
|
|
|
|
|
*
|
2019-06-09 08:31:04 -04:00
|
|
|
* @ref License
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* LICENSE
|
2016-04-04 23:09:18 -05:00
|
|
|
*
|
2019-06-11 06:48:32 -04:00
|
|
|
* Copyright (c) 2008-2019 OpenShot Studios, LLC
|
2016-04-04 23:09:18 -05:00
|
|
|
* <http://www.openshotstudios.com/>. This file is part of
|
|
|
|
|
* OpenShot Library (libopenshot), an open-source project dedicated to
|
|
|
|
|
* delivering high quality video editing and animation solutions to the
|
|
|
|
|
* world. For more information visit <http://www.openshot.org/>.
|
|
|
|
|
*
|
|
|
|
|
* OpenShot Library (libopenshot) is free software: you can redistribute it
|
|
|
|
|
* and/or modify it under the terms of the GNU Lesser General Public License
|
|
|
|
|
* as published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* OpenShot Library (libopenshot) 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 Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
* along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-10-18 07:43:37 -04:00
|
|
|
#include "ZmqLogger.h"
|
2016-04-04 23:09:18 -05:00
|
|
|
|
2019-07-23 17:11:55 -05:00
|
|
|
#if USE_RESVG == 1
|
|
|
|
|
#include "ResvgQt.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-04-04 23:09:18 -05:00
|
|
|
using namespace openshot;
|
2020-10-19 16:38:54 -04:00
|
|
|
|
2020-09-02 02:07:54 -04:00
|
|
|
#include <sstream>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <ctime>
|
|
|
|
|
#include <thread> // for std::this_thread::sleep_for
|
|
|
|
|
#include <chrono> // for std::duration::microseconds
|
2016-04-04 23:09:18 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Global reference to logger
|
|
|
|
|
ZmqLogger *ZmqLogger::m_pInstance = NULL;
|
|
|
|
|
|
|
|
|
|
// Create or Get an instance of the logger singleton
|
|
|
|
|
ZmqLogger *ZmqLogger::Instance()
|
|
|
|
|
{
|
|
|
|
|
if (!m_pInstance) {
|
|
|
|
|
// Create the actual instance of logger only once
|
|
|
|
|
m_pInstance = new ZmqLogger;
|
|
|
|
|
|
|
|
|
|
// init ZMQ variables
|
|
|
|
|
m_pInstance->context = NULL;
|
|
|
|
|
m_pInstance->publisher = NULL;
|
|
|
|
|
m_pInstance->connection = "";
|
|
|
|
|
|
|
|
|
|
// Default connection
|
|
|
|
|
m_pInstance->Connection("tcp://*:5556");
|
2016-04-21 01:39:17 -05:00
|
|
|
|
|
|
|
|
// Init enabled to False (force user to call Enable())
|
|
|
|
|
m_pInstance->enabled = false;
|
2019-07-23 17:11:55 -05:00
|
|
|
|
|
|
|
|
#if USE_RESVG == 1
|
|
|
|
|
// Init resvg logging (if needed)
|
|
|
|
|
// This can only happen 1 time or it will crash
|
|
|
|
|
ResvgRenderer::initLog();
|
|
|
|
|
#endif
|
2016-04-04 23:09:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m_pInstance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set the connection for this logger
|
2020-02-01 02:00:43 -05:00
|
|
|
void ZmqLogger::Connection(std::string new_connection)
|
2016-04-04 23:09:18 -05:00
|
|
|
{
|
|
|
|
|
// Create a scoped lock, allowing only a single thread to run the following code at one time
|
2020-02-01 02:00:43 -05:00
|
|
|
const juce::GenericScopedLock<juce::CriticalSection> lock(loggerCriticalSection);
|
2016-04-04 23:09:18 -05:00
|
|
|
|
|
|
|
|
// Does anything need to happen?
|
|
|
|
|
if (new_connection == connection)
|
|
|
|
|
return;
|
|
|
|
|
else
|
|
|
|
|
// Set new connection
|
|
|
|
|
connection = new_connection;
|
|
|
|
|
|
|
|
|
|
if (context == NULL) {
|
|
|
|
|
// Create ZMQ Context
|
|
|
|
|
context = new zmq::context_t(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (publisher != NULL) {
|
|
|
|
|
// Close an existing bound publisher socket
|
|
|
|
|
publisher->close();
|
|
|
|
|
publisher = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create new publisher instance
|
|
|
|
|
publisher = new zmq::socket_t(*context, ZMQ_PUB);
|
|
|
|
|
|
|
|
|
|
// Bind to the socket
|
|
|
|
|
try {
|
|
|
|
|
publisher->bind(connection.c_str());
|
|
|
|
|
|
|
|
|
|
} catch (zmq::error_t &e) {
|
2020-02-01 02:00:43 -05:00
|
|
|
std::cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << std::endl;
|
2016-04-04 23:09:18 -05:00
|
|
|
connection = "tcp://*:*";
|
|
|
|
|
publisher->bind(connection.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sleeping to allow connection to wake up (0.25 seconds)
|
2020-02-01 02:00:43 -05:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
2016-04-04 23:09:18 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-01 02:00:43 -05:00
|
|
|
void ZmqLogger::Log(std::string message)
|
2016-04-04 23:09:18 -05:00
|
|
|
{
|
2016-04-21 01:39:17 -05:00
|
|
|
if (!enabled)
|
|
|
|
|
// Don't do anything
|
|
|
|
|
return;
|
|
|
|
|
|
2016-04-04 23:09:18 -05:00
|
|
|
// Create a scoped lock, allowing only a single thread to run the following code at one time
|
2020-02-01 02:00:43 -05:00
|
|
|
const juce::GenericScopedLock<juce::CriticalSection> lock(loggerCriticalSection);
|
2016-04-04 23:09:18 -05:00
|
|
|
|
2016-04-12 16:42:36 -05:00
|
|
|
// Send message over socket (ZeroMQ)
|
2020-03-25 11:42:19 -04:00
|
|
|
zmq::message_t reply (message.length());
|
|
|
|
|
std::memcpy (reply.data(), message.c_str(), message.length());
|
2020-03-23 08:16:02 -04:00
|
|
|
|
2020-03-26 07:34:58 -04:00
|
|
|
#if ZMQ_VERSION > ZMQ_MAKE_VERSION(4, 3, 1)
|
2020-03-23 08:16:02 -04:00
|
|
|
// Set flags for immediate delivery (new API)
|
|
|
|
|
publisher->send(reply, zmq::send_flags::dontwait);
|
|
|
|
|
#else
|
2016-04-04 23:09:18 -05:00
|
|
|
publisher->send(reply);
|
2020-03-23 08:16:02 -04:00
|
|
|
#endif
|
2016-04-12 16:42:36 -05:00
|
|
|
|
2020-03-23 08:16:02 -04:00
|
|
|
// Also log to file, if open
|
|
|
|
|
LogToFile(message);
|
2016-11-03 02:19:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log message to a file (if path set)
|
2020-02-01 02:00:43 -05:00
|
|
|
void ZmqLogger::LogToFile(std::string message)
|
2016-11-03 02:19:48 -05:00
|
|
|
{
|
|
|
|
|
// Write to log file (if opened, and force it to write to disk in case of a crash)
|
|
|
|
|
if (log_file.is_open())
|
|
|
|
|
log_file << message << std::flush;
|
2016-04-12 16:42:36 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-01 02:00:43 -05:00
|
|
|
void ZmqLogger::Path(std::string new_path)
|
2016-04-12 16:42:36 -05:00
|
|
|
{
|
|
|
|
|
// Update path
|
|
|
|
|
file_path = new_path;
|
|
|
|
|
|
|
|
|
|
// Close file (if already open)
|
|
|
|
|
if (log_file.is_open())
|
|
|
|
|
log_file.close();
|
|
|
|
|
|
|
|
|
|
// Open file (write + append)
|
2020-02-01 02:00:43 -05:00
|
|
|
log_file.open (file_path.c_str(), std::ios::out | std::ios::app);
|
2016-04-12 16:42:36 -05:00
|
|
|
|
|
|
|
|
// Get current time and log first message
|
2020-02-01 02:00:43 -05:00
|
|
|
std::time_t now = std::time(0);
|
|
|
|
|
std::tm* localtm = std::localtime(&now);
|
|
|
|
|
log_file << "------------------------------------------" << std::endl;
|
|
|
|
|
log_file << "libopenshot logging: " << std::asctime(localtm);
|
|
|
|
|
log_file << "------------------------------------------" << std::endl;
|
2016-04-12 16:42:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ZmqLogger::Close()
|
|
|
|
|
{
|
2019-08-12 14:09:26 +03:00
|
|
|
// Disable logger as it no longer needed
|
|
|
|
|
enabled = false;
|
|
|
|
|
|
2016-04-12 16:42:36 -05:00
|
|
|
// Close file (if already open)
|
|
|
|
|
if (log_file.is_open())
|
|
|
|
|
log_file.close();
|
|
|
|
|
|
|
|
|
|
// Close socket (if any)
|
|
|
|
|
if (publisher != NULL) {
|
|
|
|
|
// Close an existing bound publisher socket
|
|
|
|
|
publisher->close();
|
|
|
|
|
publisher = NULL;
|
|
|
|
|
}
|
2016-04-21 01:39:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Append debug information
|
2020-02-01 02:00:43 -05:00
|
|
|
void ZmqLogger::AppendDebugMethod(std::string method_name,
|
2020-03-25 11:42:19 -04:00
|
|
|
std::string arg1_name, float arg1_value,
|
|
|
|
|
std::string arg2_name, float arg2_value,
|
|
|
|
|
std::string arg3_name, float arg3_value,
|
|
|
|
|
std::string arg4_name, float arg4_value,
|
|
|
|
|
std::string arg5_name, float arg5_value,
|
|
|
|
|
std::string arg6_name, float arg6_value)
|
2016-04-21 01:39:17 -05:00
|
|
|
{
|
2020-02-01 02:00:43 -05:00
|
|
|
if (!enabled && !openshot::Settings::Instance()->DEBUG_TO_STDERR)
|
2016-04-21 01:39:17 -05:00
|
|
|
// Don't do anything
|
|
|
|
|
return;
|
|
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
{
|
|
|
|
|
// Create a scoped lock, allowing only a single thread to run the following code at one time
|
2020-02-01 02:00:43 -05:00
|
|
|
const juce::GenericScopedLock<juce::CriticalSection> lock(loggerCriticalSection);
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2020-02-01 02:00:43 -05:00
|
|
|
std::stringstream message;
|
|
|
|
|
message << std::fixed << std::setprecision(4);
|
|
|
|
|
|
|
|
|
|
// Construct message
|
2016-04-24 15:37:47 -05:00
|
|
|
message << method_name << " (";
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
if (arg1_name.length() > 0)
|
|
|
|
|
message << arg1_name << "=" << arg1_value;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
if (arg2_name.length() > 0)
|
|
|
|
|
message << ", " << arg2_name << "=" << arg2_value;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
if (arg3_name.length() > 0)
|
|
|
|
|
message << ", " << arg3_name << "=" << arg3_value;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
if (arg4_name.length() > 0)
|
|
|
|
|
message << ", " << arg4_name << "=" << arg4_value;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
if (arg5_name.length() > 0)
|
|
|
|
|
message << ", " << arg5_name << "=" << arg5_value;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2016-04-24 15:37:47 -05:00
|
|
|
if (arg6_name.length() > 0)
|
|
|
|
|
message << ", " << arg6_name << "=" << arg6_value;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2020-02-01 02:00:43 -05:00
|
|
|
message << ")" << std::endl;
|
2016-04-21 01:39:17 -05:00
|
|
|
|
2020-02-01 02:00:43 -05:00
|
|
|
if (openshot::Settings::Instance()->DEBUG_TO_STDERR) {
|
|
|
|
|
// Print message to stderr
|
|
|
|
|
std::clog << message.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enabled) {
|
|
|
|
|
// Send message through ZMQ
|
|
|
|
|
Log(message.str());
|
|
|
|
|
}
|
2016-04-24 15:37:47 -05:00
|
|
|
}
|
ZmqLogger: default AppendDebugMethod()'s extra params
Give the AppendDebugMethod() declaration a set of default values for
all parameters after the first. (It uses `""` and `-1.0`, which are
what callers were passing in anyway.) This way, callers have the
_option_ to eschew this kind of thing:
```
ZmqLogger::Instance()->AppendDebugMethod("Message", "start", start,
"length", length, "", -1, "", -1, "", -1, "", -1);
```
instead, they can use the functionally equivalent:
```
ZmqLogger::Instance()->AppendDebugMethod("Message", "start", start,
"length", length);
```
Passing meaningless args is the compiler's job, not the programmer's.
2019-07-03 14:06:44 -04:00
|
|
|
}
|