1 /*
2 * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
3 * Copyright (C) 2011 Pete Shorthose
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * ---------------------------------------------------------------------------
19 */
20
21 #include "gx_logging.h"
22 #include <iostream>
23 #include <iomanip>
24
25 /****************************************************************
26 ** Logging
27 */
28
GxLogger()29 GxLogger::GxLogger()
30 : trackable(),
31 msglist(),
32 msgmutex(),
33 got_new_msg(),
34 ui_thread(),
35 handlers(),
36 queue_all_msgs(true) {
37 }
38
39 static class GxLoggerGuard {
40 private:
41 GxLogger *logger_instance;
42 public:
GxLoggerGuard()43 GxLoggerGuard() : logger_instance(0) {}
~GxLoggerGuard()44 ~GxLoggerGuard() { destroy(); }
create()45 void create() { logger_instance = new GxLogger; }
destroy()46 void destroy() { if (logger_instance) { delete logger_instance; logger_instance = 0; }}
get()47 GxLogger *get() { return logger_instance; }
48 } logger_guard;
49
get_logger()50 GxLogger& GxLogger::get_logger() {
51 GxLogger *l = logger_guard.get();
52 if (!l) {
53 logger_guard.create();
54 l = logger_guard.get();
55 }
56 return *l;
57 }
58
destroy()59 void GxLogger::destroy() {
60 logger_guard.destroy();
61 }
62
~GxLogger()63 GxLogger::~GxLogger() {
64 delete got_new_msg;
65 }
66
set_ui_thread()67 void GxLogger::set_ui_thread() {
68 if (ui_thread) {
69 assert(pthread_equal(pthread_self(), ui_thread));
70 } else {
71 got_new_msg = new Glib::Dispatcher;
72 ui_thread = pthread_self();
73 got_new_msg->connect(mem_fun(*this, &GxLogger::write_queued));
74 }
75 }
76
signal_message()77 GxLogger::msg_signal& GxLogger::signal_message() {
78 set_ui_thread();
79 return handlers;
80 }
81
unplug_queue()82 void GxLogger::unplug_queue() {
83 if (!queue_all_msgs) {
84 return;
85 }
86 queue_all_msgs = false;
87 write_queued();
88 }
89
write_queued()90 void GxLogger::write_queued() {
91 if (handlers.empty()) {
92 return;
93 }
94
95 // quick copy list
96 msgmutex.lock();
97 std::list<logmsg*> l = msglist;
98 if (!queue_all_msgs) {
99 msglist.clear();
100 }
101 msgmutex.unlock();
102
103 // feed throught the handler(s)
104 for (std::list<logmsg*>::iterator i = l.begin(); i != l.end(); ++i) {
105 if (queue_all_msgs) {
106 if (!(*i)->plugged) {
107 handlers((*i)->msg, (*i)->msgtype, (*i)->plugged);
108 (*i)->plugged = true;
109 }
110 } else {
111 handlers((*i)->msg, (*i)->msgtype, (*i)->plugged);
112 delete *i;
113 }
114 }
115 }
116
format(const char * func,const std::string & msg)117 std::string GxLogger::format(const char* func, const std::string& msg) {
118 // timestamp
119 time_t now;
120 time(&now);
121 struct tm *tm_now = localtime(&now);
122 std::ostringstream msgbuf;
123 msgbuf << "[" << std::setfill('0')
124 << std::setw(2) << tm_now->tm_hour << ":"
125 << std::setw(2) << tm_now->tm_min << ":"
126 << std::setw(2) << tm_now->tm_sec << "]"
127 << " " << func << " *** " << msg;
128 return msgbuf.str();
129 }
130
print(const char * func,const std::string & msg,GxLogger::MsgType msgtype)131 void GxLogger::print(const char* func, const std::string& msg, GxLogger::MsgType msgtype) {
132 GxLogger::print(format(func, msg), msgtype);
133 }
134
print(const std::string & formatted_msg,GxLogger::MsgType msgtype)135 void GxLogger::print(const std::string& formatted_msg, GxLogger::MsgType msgtype) {
136 if (handlers.empty() || !(pthread_equal(pthread_self(), ui_thread))) {
137 boost::mutex::scoped_lock lock(msgmutex);
138 // defer output
139 msglist.push_back(new logmsg(formatted_msg, msgtype, false));
140 if (!handlers.empty() && msglist.size() == 1) {
141 (*got_new_msg)();
142 }
143 } else {
144 write_queued();
145 handlers(formatted_msg, msgtype, false);
146 if (queue_all_msgs) {
147 msglist.push_back(new logmsg(formatted_msg, msgtype, true));
148 }
149 }
150 }
151
152 /*
153 ** utility logger functions
154 */
155
156 // ---- log message handler
gx_print_logmsg(const char * func,const std::string & msg,GxLogger::MsgType msgtype)157 void gx_print_logmsg(const char* func, const std::string& msg, GxLogger::MsgType msgtype) {
158 GxLogger::get_logger().print(func, msg, msgtype);
159 }
160
161 // warning
gx_print_warning(const char * func,const std::string & msg)162 void gx_print_warning(const char* func, const std::string& msg) {
163 gx_print_logmsg(func, msg, GxLogger::kWarning);
164 }
165
166 // error
gx_print_error(const char * func,const std::string & msg)167 void gx_print_error(const char* func, const std::string& msg) {
168 gx_print_logmsg(func, msg, GxLogger::kError);
169 }
170
~GxFatalError()171 GxFatalError::~GxFatalError() throw() {
172 }
173
174 // fatal error
175 // - do not use before Gtk::Main() ctor
176 // - do not use when main loop is blocked (modal dialog or something)
177 //
gx_print_fatal(const char * func,const std::string & msg)178 void gx_print_fatal(const char* func, const std::string& msg) {
179 std::string msgbuf = std::string(_("fatal system error: ")) + func + " *** " + msg + "\n";
180 GxExit::get_instance().fatal_msg(msgbuf);
181 }
182
183 // info
gx_print_info(const char * func,const std::string & msg)184 void gx_print_info(const char* func, const std::string& msg) {
185 gx_print_logmsg(func, msg, GxLogger::kInfo);
186 }
187
188
189 /****************************************************************
190 ** class GxExit
191 */
192
GxExit()193 GxExit::GxExit(): exit_sig(), ui_thread() {}
194
~GxExit()195 GxExit::~GxExit() {}
196
exit_program(std::string msg,int errcode)197 void GxExit::exit_program(std::string msg, int errcode) {
198 exit_sig.emit_reverse(!pthread_equal(pthread_self(), ui_thread));
199 if (msg.empty()) {
200 msg = "** guitarix exit **";
201 }
202 std::cerr << msg << std::endl;
203 _exit(errcode);
204 }
205
get_instance()206 GxExit& GxExit::get_instance() {
207 static GxExit instance;
208 return instance;
209 }
210