OpenShot Library | libopenshot  0.2.5
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 "../include/ZmqLogger.h"
32 
33 #if USE_RESVG == 1
34  #include "ResvgQt.h"
35 #endif
36 
37 using namespace std;
38 using namespace openshot;
39 
40 
41 // Global reference to logger
42 ZmqLogger *ZmqLogger::m_pInstance = NULL;
43 
44 // Create or Get an instance of the logger singleton
45 ZmqLogger *ZmqLogger::Instance()
46 {
47  if (!m_pInstance) {
48  // Create the actual instance of logger only once
49  m_pInstance = new ZmqLogger;
50 
51  // init ZMQ variables
52  m_pInstance->context = NULL;
53  m_pInstance->publisher = NULL;
54  m_pInstance->connection = "";
55 
56  // Default connection
57  m_pInstance->Connection("tcp://*:5556");
58 
59  // Init enabled to False (force user to call Enable())
60  m_pInstance->enabled = false;
61 
62  #if USE_RESVG == 1
63  // Init resvg logging (if needed)
64  // This can only happen 1 time or it will crash
65  ResvgRenderer::initLog();
66  #endif
67 
68  }
69 
70  return m_pInstance;
71 }
72 
73 // Set the connection for this logger
74 void ZmqLogger::Connection(string new_connection)
75 {
76  // Create a scoped lock, allowing only a single thread to run the following code at one time
77  const GenericScopedLock<CriticalSection> lock(loggerCriticalSection);
78 
79  // Does anything need to happen?
80  if (new_connection == connection)
81  return;
82  else
83  // Set new connection
84  connection = new_connection;
85 
86  if (context == NULL) {
87  // Create ZMQ Context
88  context = new zmq::context_t(1);
89  }
90 
91  if (publisher != NULL) {
92  // Close an existing bound publisher socket
93  publisher->close();
94  publisher = NULL;
95  }
96 
97  // Create new publisher instance
98  publisher = new zmq::socket_t(*context, ZMQ_PUB);
99 
100  // Bind to the socket
101  try {
102  publisher->bind(connection.c_str());
103 
104  } catch (zmq::error_t &e) {
105  cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << endl;
106  connection = "tcp://*:*";
107  publisher->bind(connection.c_str());
108  }
109 
110  // Sleeping to allow connection to wake up (0.25 seconds)
111  usleep(250000);
112 }
113 
114 void ZmqLogger::Log(string message)
115 {
116  if (!enabled)
117  // Don't do anything
118  return;
119 
120  // Create a scoped lock, allowing only a single thread to run the following code at one time
121  const GenericScopedLock<CriticalSection> lock(loggerCriticalSection);
122 
123  // Send message over socket (ZeroMQ)
124  zmq::message_t reply (message.length());
125  memcpy (reply.data(), message.c_str(), message.length());
126  publisher->send(reply);
127 
128  // Write to log file (if opened, and force it to write to disk in case of a crash)
129  if (log_file.is_open())
130  log_file << message << std::flush;
131 }
132 
133 // Log message to a file (if path set)
134 void ZmqLogger::LogToFile(string message)
135 {
136  // Write to log file (if opened, and force it to write to disk in case of a crash)
137  if (log_file.is_open())
138  log_file << message << std::flush;
139 }
140 
141 void ZmqLogger::Path(string new_path)
142 {
143  // Update path
144  file_path = new_path;
145 
146  // Close file (if already open)
147  if (log_file.is_open())
148  log_file.close();
149 
150  // Open file (write + append)
151  log_file.open (file_path.c_str(), ios::out | ios::app);
152 
153  // Get current time and log first message
154  time_t now = time(0);
155  tm* localtm = localtime(&now);
156  log_file << "------------------------------------------" << endl;
157  log_file << "libopenshot logging: " << asctime(localtm);
158  log_file << "------------------------------------------" << endl;
159 }
160 
161 void ZmqLogger::Close()
162 {
163  // Disable logger as it no longer needed
164  enabled = false;
165 
166  // Close file (if already open)
167  if (log_file.is_open())
168  log_file.close();
169 
170  // Close socket (if any)
171  if (publisher != NULL) {
172  // Close an existing bound publisher socket
173  publisher->close();
174  publisher = NULL;
175  }
176 }
177 
178 // Append debug information
179 void ZmqLogger::AppendDebugMethod(string method_name,
180  string arg1_name, float arg1_value,
181  string arg2_name, float arg2_value,
182  string arg3_name, float arg3_value,
183  string arg4_name, float arg4_value,
184  string arg5_name, float arg5_value,
185  string arg6_name, float arg6_value)
186 {
187  if (!enabled)
188  // Don't do anything
189  return;
190 
191  {
192  // Create a scoped lock, allowing only a single thread to run the following code at one time
193  const GenericScopedLock<CriticalSection> lock(loggerCriticalSection);
194 
195  stringstream message;
196  message << fixed << setprecision(4);
197  message << method_name << " (";
198 
199  // Add attributes to method JSON
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  // Output to standard output
219  message << ")" << endl;
220 
221  // Send message through ZMQ
222  Log(message.str());
223  }
224 }
This class is used for logging and sending those logs over a ZemoMQ socket to a listener.
Definition: ZmqLogger.h:56
This namespace is the default namespace for all code in the openshot library.