First commit
[anna.git] / source / core / tracing / Logger.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <unistd.h>
38
39 #include <anna/core/tracing/Logger.hpp>
40 #include <anna/core/RuntimeException.hpp>
41 #include <anna/core/DataBlock.hpp>
42 #include <anna/core/tracing/TraceLogger.hpp>
43 #include <anna/core/functions.hpp>
44
45 using namespace anna;
46
47 Logger::Writer* Logger::st_writer = NULL;
48 bool Logger::st_enabled(true);
49
50 #ifndef _MT
51 pid_t Logger::st_pid(-1);
52 #endif
53
54 #ifdef _DEBUG
55 Logger::Level Logger::st_level(Logger::Debug);
56 #else
57 Logger::Level Logger::st_level(Logger::Warning);
58 #endif
59
60 NRMutex Logger::st_mutex;
61
62 void Logger::initialize(const char* ident)
63 throw() {
64   if(st_writer == NULL) {
65     st_writer = new TraceLogger;
66     st_writer->initialize(ident);
67   }
68 }
69
70 void Logger::initialize(const char* ident, Writer* writer)
71 throw() {
72   if(st_writer == NULL && writer != NULL) {
73     writer->initialize(ident);
74     st_writer = writer;
75   }
76 }
77
78 void Logger::showPID(const bool show)
79 throw() {
80 #ifndef _MT
81
82   if(show == true) {
83     if(st_pid == -1)
84       st_pid = getpid();
85   } else
86     st_pid = -1;
87
88 #endif
89 }
90
91 void Logger::write(const Level level, const char* text, const char* fromFile, const int fromLine)
92 throw() {
93 #ifndef _MT
94
95   if(isActive(level) && st_writer != NULL) {
96     if(st_pid == -1)
97       st_writer->do_write(level, "%s (%d) | %s", fromFile, fromLine, text);
98     else
99       st_writer->do_write(level, "%s (%d) | pid: %d | %s", fromFile, fromLine, st_pid, text);
100   }
101
102 #else
103
104   if(isActive(level) && st_writer != NULL)
105     st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s", fromFile, fromLine, (unsigned int) pthread_self(), text);
106
107 #endif
108 }
109
110 void Logger::write(const Level level, const char* text, const char* value, const char* fromFile, const int fromLine)
111 throw() {
112 #ifndef _MT
113
114   if(isActive(level) && st_writer != NULL) {
115     if(st_pid == -1)
116       st_writer->do_write(level, "%s (%d) | %s | %s", fromFile, fromLine, text, value);
117     else
118       st_writer->do_write(level, "%s (%d) | pid: %d | %s | %s", fromFile, fromLine, st_pid, text, value);
119   }
120
121 #else
122
123   if(isActive(level) && st_writer != NULL)
124     st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | %s", fromFile, fromLine, (unsigned int) pthread_self(), text, value);
125
126 #endif
127 }
128
129 void Logger::write(const Level level, const char* text, const int value, const char* fromFile, const int fromLine)
130 throw() {
131 #ifndef _MT
132
133   if(isActive(level) && st_writer != NULL) {
134     if(st_pid == -1)
135       st_writer->do_write(level, "%s (%d) | %s | %d (%x)", fromFile, fromLine, text, value, value);
136     else
137       st_writer->do_write(level, "%s (%d) | pid: %d | %s | %d (%x)", fromFile, fromLine, st_pid, text, value, value);
138   }
139
140 #else
141
142   if(isActive(level) && st_writer != NULL)
143     st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | %d (%x)", fromFile, fromLine, (unsigned int) pthread_self(), text, value, value);
144
145 #endif
146 }
147
148 void Logger::write(const Level level, const char* text, const DataBlock& value, const char* fromFile, const int fromLine)
149 throw() {
150   if(isActive(level) && st_writer != NULL) {
151 #ifndef _MT
152
153     try {
154       st_writer->do_write(level, "%s (%d) | %s | Data block: %s", fromFile, fromLine, text, functions::asString(value).c_str());
155     } catch(...) {
156       st_writer->do_write(level, "%s (%d) | %s | Data block: <fault!>", fromFile, fromLine, text);
157     }
158
159 #else
160
161     try {
162       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());
163     } catch(...) {
164       st_writer->do_write(level, "%s (%d) | thr: 0x%x | %s | Data block: <fault!>", fromFile, fromLine, (unsigned int) pthread_self(), text);
165     }
166
167 #endif
168   }
169 }
170
171 void Logger::disable()
172 throw(RuntimeException) {
173   st_mutex.lock();
174   st_enabled = false;
175   st_mutex.unlock();
176 }
177
178 void Logger::enable()
179 throw(RuntimeException) {
180   st_mutex.lock();
181   st_enabled = true;
182   st_mutex.unlock();
183 }
184
185 Logger::Level Logger::asLevel(const char* stringLevel)
186 throw(RuntimeException) {
187   static struct {
188     const char* stringLevel;
189     const Level level;
190   } values [] = {
191     { "emergency", Emergency }, { "alert", Alert }, { "critical", Critical }, { "error", Error },
192     { "warning", Warning }, { "notice", Notice }, { "information", Information }, { "debug", Debug },
193     { "local0", Local0 }, { "local1", Local1 }, { "local2", Local2 }, { "local3", Local3 },
194     { "local4", Local4 }, { "local5", Local5 }, { "local6", Local6 }, { "local7", Local7 },
195     { NULL, (Level) - 1  }
196   };
197   int i = 0;
198
199   while(values [i].stringLevel != NULL) {
200     if(strcasecmp(stringLevel, values [i].stringLevel) == 0)
201       break;
202
203     i ++;
204   }
205
206   if(values [i].stringLevel == NULL) {
207     std::string msg = "Level not registered: '";
208     msg += stringLevel;
209     msg += "'. Possible values: ";
210
211     for(i = 0; values [i].stringLevel != NULL; i ++) {
212       msg += values [i].stringLevel;
213       msg += ' ';
214     }
215
216     throw RuntimeException(msg, ANNA_FILE_LOCATION);
217   }
218
219   return values [i].level;
220 }
221
222 const char* Logger::asString(const Level level)
223 throw() {
224   static const char* levels [] = {
225     "Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Information", "Debug"
226   };
227   static struct {
228     const char* stringLevel;
229     const Level level;
230   } values [] = {
231     { "Local0", Local0 }, { "Local1", Local1 }, { "Local2", Local2 }, { "Local3", Local3 },
232     { "Local4", Local4 }, { "Local5", Local5 }, { "Local6", Local6 }, { "Local7", Local7 },
233     { NULL, (Level) - 1  }
234   };
235   const char* result = NULL;
236
237   if(level >= Emergency && level <= Debug)
238     result = levels [level];
239   else {
240     for(int i = 0; values [i].stringLevel != NULL; i ++) {
241       if(level == values [i].level) {
242         result = values [i].stringLevel;
243         break;
244       }
245     }
246
247     if(result == NULL)
248       result = "Other";
249   }
250
251   return result;
252 }
253
254 Logger::Writer::Writer(const int bufferSize) {
255   try {
256     a_dataBlock = new DataBlock(true);
257     a_dataBlock->allocate(bufferSize);
258   } catch(Exception&) {
259   }
260 }
261
262 Logger::Writer::Writer() {
263   try {
264     a_dataBlock = new DataBlock(true);
265     a_dataBlock->allocate(1024);
266   } catch(Exception&) {
267   }
268 }
269
270 Logger::Writer::~Writer() {
271   Logger::st_writer = NULL;
272 }
273