OpenShot Library | libopenshot  0.2.7
ZmqLogger.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for ZeroMQ-based Logger class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  *
6  * @ref License
7  */
8 
9 /* LICENSE
10  *
11  * Copyright (c) 2008-2019 OpenShot Studios, LLC
12  * <http://www.openshotstudios.com/>. This file is part of
13  * OpenShot Library (libopenshot), an open-source project dedicated to
14  * delivering high quality video editing and animation solutions to the
15  * world. For more information visit <http://www.openshot.org/>.
16  *
17  * OpenShot Library (libopenshot) is free software: you can redistribute it
18  * and/or modify it under the terms of the GNU Lesser General Public License
19  * as published by the Free Software Foundation, either version 3 of the
20  * License, or (at your option) any later version.
21  *
22  * OpenShot Library (libopenshot) is distributed in the hope that it will be
23  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 #include "ZmqLogger.h"
32 #include "Exceptions.h"
33 
34 #if USE_RESVG == 1
35  #include "ResvgQt.h"
36 #endif
37 
38 using namespace openshot;
39 
40 #include <sstream>
41 #include <iostream>
42 #include <iomanip>
43 #include <ctime>
44 #include <thread> // for std::this_thread::sleep_for
45 #include <chrono> // for std::duration::microseconds
46 
47 
48 // Global reference to logger
49 ZmqLogger *ZmqLogger::m_pInstance = NULL;
50 
51 // Create or Get an instance of the logger singleton
53 {
54  if (!m_pInstance) {
55  // Create the actual instance of logger only once
56  m_pInstance = new ZmqLogger;
57 
58  // init ZMQ variables
59  m_pInstance->context = NULL;
60  m_pInstance->publisher = NULL;
61  m_pInstance->connection = "";
62 
63  // Default connection
64  m_pInstance->Connection("tcp://*:5556");
65 
66  // Init enabled to False (force user to call Enable())
67  m_pInstance->enabled = false;
68 
69  #if USE_RESVG == 1
70  // Init resvg logging (if needed)
71  // This can only happen 1 time or it will crash
72  ResvgRenderer::initLog();
73  #endif
74  }
75 
76  return m_pInstance;
77 }
78 
79 // Set the connection for this logger
80 void ZmqLogger::Connection(std::string new_connection)
81 {
82  // Create a scoped lock, allowing only a single thread to run the following code at one time
83  const juce::GenericScopedLock<juce::CriticalSection> lock(loggerCriticalSection);
84 
85  // Does anything need to happen?
86  if (new_connection == connection)
87  return;
88  else
89  // Set new connection
90  connection = new_connection;
91 
92  if (context == NULL) {
93  // Create ZMQ Context
94  context = new zmq::context_t(1);
95  }
96 
97  if (publisher != NULL) {
98  // Close an existing bound publisher socket
99  publisher->close();
100  publisher = NULL;
101  }
102 
103  // Create new publisher instance
104  publisher = new zmq::socket_t(*context, ZMQ_PUB);
105 
106  // Bind to the socket
107  try {
108  publisher->bind(connection.c_str());
109 
110  } catch (zmq::error_t &e) {
111  std::cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << std::endl;
112  connection = "tcp://*:*";
113  publisher->bind(connection.c_str());
114  }
115 
116  // Sleeping to allow connection to wake up (0.25 seconds)
117  std::this_thread::sleep_for(std::chrono::milliseconds(250));
118 }
119 
120 void ZmqLogger::Log(std::string message)
121 {
122  if (!enabled)
123  // Don't do anything
124  return;
125 
126  // Create a scoped lock, allowing only a single thread to run the following code at one time
127  const juce::GenericScopedLock<juce::CriticalSection> lock(loggerCriticalSection);
128 
129  // Send message over socket (ZeroMQ)
130  zmq::message_t reply (message.length());
131  std::memcpy (reply.data(), message.c_str(), message.length());
132 
133 #if ZMQ_VERSION > ZMQ_MAKE_VERSION(4, 3, 1)
134  // Set flags for immediate delivery (new API)
135  publisher->send(reply, zmq::send_flags::dontwait);
136 #else
137  publisher->send(reply);
138 #endif
139 
140  // Also log to file, if open
141  LogToFile(message);
142 }
143 
144 // Log message to a file (if path set)
145 void ZmqLogger::LogToFile(std::string message)
146 {
147  // Write to log file (if opened, and force it to write to disk in case of a crash)
148  if (log_file.is_open())
149  log_file << message << std::flush;
150 }
151 
152 void ZmqLogger::Path(std::string new_path)
153 {
154  // Update path
155  file_path = new_path;
156 
157  // Close file (if already open)
158  if (log_file.is_open())
159  log_file.close();
160 
161  // Open file (write + append)
162  log_file.open (file_path.c_str(), std::ios::out | std::ios::app);
163 
164  // Get current time and log first message
165  std::time_t now = std::time(0);
166  std::tm* localtm = std::localtime(&now);
167  log_file << "------------------------------------------" << std::endl;
168  log_file << "libopenshot logging: " << std::asctime(localtm);
169  log_file << "------------------------------------------" << std::endl;
170 }
171 
173 {
174  // Disable logger as it no longer needed
175  enabled = false;
176 
177  // Close file (if already open)
178  if (log_file.is_open())
179  log_file.close();
180 
181  // Close socket (if any)
182  if (publisher != NULL) {
183  // Close an existing bound publisher socket
184  publisher->close();
185  publisher = NULL;
186  }
187 }
188 
189 // Append debug information
190 void ZmqLogger::AppendDebugMethod(std::string method_name,
191  std::string arg1_name, float arg1_value,
192  std::string arg2_name, float arg2_value,
193  std::string arg3_name, float arg3_value,
194  std::string arg4_name, float arg4_value,
195  std::string arg5_name, float arg5_value,
196  std::string arg6_name, float arg6_value)
197 {
198  if (!enabled && !openshot::Settings::Instance()->DEBUG_TO_STDERR)
199  // Don't do anything
200  return;
201 
202  {
203  // Create a scoped lock, allowing only a single thread to run the following code at one time
204  const juce::GenericScopedLock<juce::CriticalSection> lock(loggerCriticalSection);
205 
206  std::stringstream message;
207  message << std::fixed << std::setprecision(4);
208 
209  // Construct message
210  message << method_name << " (";
211 
212  if (arg1_name.length() > 0)
213  message << arg1_name << "=" << arg1_value;
214 
215  if (arg2_name.length() > 0)
216  message << ", " << arg2_name << "=" << arg2_value;
217 
218  if (arg3_name.length() > 0)
219  message << ", " << arg3_name << "=" << arg3_value;
220 
221  if (arg4_name.length() > 0)
222  message << ", " << arg4_name << "=" << arg4_value;
223 
224  if (arg5_name.length() > 0)
225  message << ", " << arg5_name << "=" << arg5_value;
226 
227  if (arg6_name.length() > 0)
228  message << ", " << arg6_name << "=" << arg6_value;
229 
230  message << ")" << std::endl;
231 
232  if (openshot::Settings::Instance()->DEBUG_TO_STDERR) {
233  // Print message to stderr
234  std::clog << message.str();
235  }
236 
237  if (enabled) {
238  // Send message through ZMQ
239  Log(message.str());
240  }
241  }
242 }
Header file for all Exception classes.
Header file for ZeroMQ-based Logger class.
static Settings * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: Settings.cpp:41
This class is used for logging and sending those logs over a ZemoMQ socket to a listener.
Definition: ZmqLogger.h:57
void Close()
Close logger (sockets and/or files)
Definition: ZmqLogger.cpp:172
void Log(std::string message)
Log message to all subscribers of this logger (if any)
Definition: ZmqLogger.cpp:120
void Path(std::string new_path)
Set or change the file path (optional)
Definition: ZmqLogger.cpp:152
void LogToFile(std::string message)
Log message to a file (if path set)
Definition: ZmqLogger.cpp:145
void Connection(std::string new_connection)
Set or change connection info for logger (i.e. tcp://*:5556)
Definition: ZmqLogger.cpp:80
void AppendDebugMethod(std::string method_name, std::string arg1_name="", float arg1_value=-1.0, std::string arg2_name="", float arg2_value=-1.0, std::string arg3_name="", float arg3_value=-1.0, std::string arg4_name="", float arg4_value=-1.0, std::string arg5_name="", float arg5_value=-1.0, std::string arg6_name="", float arg6_value=-1.0)
Append debug information.
Definition: ZmqLogger.cpp:190
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: ZmqLogger.cpp:52
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:47