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