Fix retransmission issues (order, tracing, etc.)
[anna.git] / source / core / tracing / Logger.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <unistd.h>
10
11 #include <anna/core/tracing/Logger.hpp>
12 #include <anna/core/RuntimeException.hpp>
13 #include <anna/core/DataBlock.hpp>
14 #include <anna/core/tracing/TraceLogger.hpp>
15 #include <anna/core/functions.hpp>
16
17 using namespace anna;
18
19 Logger::Writer* Logger::st_writer = NULL;
20 bool Logger::st_enabled(true);
21
22 #ifndef _MT
23 pid_t Logger::st_pid(-1);
24 #endif
25
26 #ifdef _DEBUG
27 Logger::Level Logger::st_level(Logger::Debug);
28 #else
29 Logger::Level Logger::st_level(Logger::Warning);
30 #endif
31
32 NRMutex Logger::st_mutex;
33
34 void Logger::initialize(const char* ident)
35 throw() {
36   if(st_writer == NULL) {
37     st_writer = new TraceLogger;
38     st_writer->initialize(ident);
39   }
40 }
41
42 void Logger::initialize(const char* ident, Writer* writer)
43 throw() {
44   if(st_writer == NULL && writer != NULL) {
45     writer->initialize(ident);
46     st_writer = writer;
47   }
48 }
49
50 void Logger::showPID(const bool show)
51 throw() {
52 #ifndef _MT
53
54   if(show == true) {
55     if(st_pid == -1)
56       st_pid = getpid();
57   } else
58     st_pid = -1;
59
60 #endif
61 }
62
63 void Logger::write(const Level level, const char* text, const char* fromFile, const int fromLine)
64 throw() {
65 #ifndef _MT
66
67   if(isActive(level) && st_writer != NULL) {
68     if(st_pid == -1)
69       st_writer->do_write(level, "%s (%d) | %s", fromFile, fromLine, text);
70     else
71       st_writer->do_write(level, "%s (%d) | pid: %d | %s", fromFile, fromLine, st_pid, text);
72   }
73
74 #else
75
76   if(isActive(level) && st_writer != NULL)
77     st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s", fromFile, fromLine, (unsigned int) pthread_self(), text);
78
79 #endif
80 }
81
82 void Logger::write(const Level level, const char* text, const char* value, const char* fromFile, const int fromLine)
83 throw() {
84 #ifndef _MT
85
86   if(isActive(level) && st_writer != NULL) {
87     if(st_pid == -1)
88       st_writer->do_write(level, "%s (%d) | %s | %s", fromFile, fromLine, text, value);
89     else
90       st_writer->do_write(level, "%s (%d) | pid: %d | %s | %s", fromFile, fromLine, st_pid, text, value);
91   }
92
93 #else
94
95   if(isActive(level) && st_writer != NULL)
96     st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | %s", fromFile, fromLine, (unsigned int) pthread_self(), text, value);
97
98 #endif
99 }
100
101 void Logger::write(const Level level, const char* text, const int value, const char* fromFile, const int fromLine)
102 throw() {
103 #ifndef _MT
104
105   if(isActive(level) && st_writer != NULL) {
106     if(st_pid == -1)
107       st_writer->do_write(level, "%s (%d) | %s | %d (%x)", fromFile, fromLine, text, value, value);
108     else
109       st_writer->do_write(level, "%s (%d) | pid: %d | %s | %d (%x)", fromFile, fromLine, st_pid, text, value, value);
110   }
111
112 #else
113
114   if(isActive(level) && st_writer != NULL)
115     st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | %d (%x)", fromFile, fromLine, (unsigned int) pthread_self(), text, value, value);
116
117 #endif
118 }
119
120 void Logger::write(const Level level, const char* text, const DataBlock& value, const char* fromFile, const int fromLine)
121 throw() {
122   if(isActive(level) && st_writer != NULL) {
123 #ifndef _MT
124
125     try {
126       st_writer->do_write(level, "%s (%d) | %s | Data block: %s", fromFile, fromLine, text, functions::asString(value).c_str());
127     } catch(...) {
128       st_writer->do_write(level, "%s (%d) | %s | Data block: <fault!>", fromFile, fromLine, text);
129     }
130
131 #else
132
133     try {
134       st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | Data block: %s", fromFile, fromLine, (unsigned int) pthread_self(), text, functions::asString(value).c_str());
135     } catch(...) {
136       st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | Data block: <fault!>", fromFile, fromLine, (unsigned int) pthread_self(), text);
137     }
138
139 #endif
140   }
141 }
142
143 void Logger::disable()
144 throw(RuntimeException) {
145   st_mutex.lock();
146   st_enabled = false;
147   st_mutex.unlock();
148 }
149
150 void Logger::enable()
151 throw(RuntimeException) {
152   st_mutex.lock();
153   st_enabled = true;
154   st_mutex.unlock();
155 }
156
157 Logger::Level Logger::asLevel(const char* stringLevel)
158 throw(RuntimeException) {
159   static struct {
160     const char* stringLevel;
161     const Level level;
162   } values [] = {
163     { "emergency", Emergency }, { "alert", Alert }, { "critical", Critical }, { "error", Error },
164     { "warning", Warning }, { "notice", Notice }, { "information", Information }, { "debug", Debug },
165     { "local0", Local0 }, { "local1", Local1 }, { "local2", Local2 }, { "local3", Local3 },
166     { "local4", Local4 }, { "local5", Local5 }, { "local6", Local6 }, { "local7", Local7 },
167     { NULL, (Level) - 1  }
168   };
169   int i = 0;
170
171   while(values [i].stringLevel != NULL) {
172     if(strcasecmp(stringLevel, values [i].stringLevel) == 0)
173       break;
174
175     i ++;
176   }
177
178   if(values [i].stringLevel == NULL) {
179     std::string msg = "Level not registered: '";
180     msg += stringLevel;
181     msg += "'. Possible values: ";
182
183     for(i = 0; values [i].stringLevel != NULL; i ++) {
184       msg += values [i].stringLevel;
185       msg += ' ';
186     }
187
188     throw RuntimeException(msg, ANNA_FILE_LOCATION);
189   }
190
191   return values [i].level;
192 }
193
194 const char* Logger::asString(const Level level)
195 throw() {
196   static const char* levels [] = {
197     "Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Information", "Debug"
198   };
199   static struct {
200     const char* stringLevel;
201     const Level level;
202   } values [] = {
203     { "Local0", Local0 }, { "Local1", Local1 }, { "Local2", Local2 }, { "Local3", Local3 },
204     { "Local4", Local4 }, { "Local5", Local5 }, { "Local6", Local6 }, { "Local7", Local7 },
205     { NULL, (Level) - 1  }
206   };
207   const char* result = NULL;
208
209   if(level >= Emergency && level <= Debug)
210     result = levels [level];
211   else {
212     for(int i = 0; values [i].stringLevel != NULL; i ++) {
213       if(level == values [i].level) {
214         result = values [i].stringLevel;
215         break;
216       }
217     }
218
219     if(result == NULL)
220       result = "Other";
221   }
222
223   return result;
224 }
225
226 Logger::Writer::Writer(const int bufferSize) {
227   try {
228     a_dataBlock = new DataBlock(true);
229     a_dataBlock->allocate(bufferSize);
230   } catch(Exception&) {
231   }
232 }
233
234 Logger::Writer::Writer() {
235   try {
236     a_dataBlock = new DataBlock(true);
237     a_dataBlock->allocate(1024);
238   } catch(Exception&) {
239   }
240 }
241
242 Logger::Writer::~Writer() {
243   Logger::st_writer = NULL;
244 }
245