Remove warnings
[anna.git] / source / core / tracing / TraceWriter.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 <stdarg.h>
10 #include <stdio.h>
11 #include <iostream>
12
13 #include <limits.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <fcntl.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19
20 #include <anna/core/tracing/TraceWriter.hpp>
21 #include <anna/core/DataBlock.hpp>
22 #include <anna/core/functions.hpp>
23 #include <anna/core/util/Configuration.hpp>
24 #include <anna/core/tracing/TraceWriterObserver.hpp>
25
26 using namespace std;
27 using namespace anna;
28
29 TraceWriter::TraceWriter() :
30   a_maxSize(DefaultMaxKBSize),
31   a_stream(-1),
32   a_lastTime(0),
33   a_observed(false) {
34   string file;
35   file = "/var/tmp/anna.process.";
36   file += functions::asString((int) getpid());
37   file += ".log";
38   setup(file.c_str(), DefaultMaxKBSize, false);
39 }
40
41 TraceWriter::TraceWriter(const char* fileName, const int maxSize) :
42   a_maxSize(DefaultMaxKBSize),
43   a_stream(-1),
44   a_lastTime(0),
45   a_observed(false) {
46   setup(fileName, maxSize, false);
47 }
48
49 void TraceWriter::setup(const char* fileName, const Configuration& configuration)
50 throw() {
51   int maxSize = a_maxSize;
52   bool clean = true;
53
54   try {
55     try {
56       maxSize = (configuration.getIntegerValue("Trace", "MaxFileSize") << 10);
57     } catch(...) {
58     }
59
60     try {
61       Logger::setLevel(Logger::asLevel(configuration.getValue("Trace", "Level")));
62     } catch(Exception& ex) {
63       ex.trace();
64     }
65
66     try {
67       clean = (configuration.getIntegerValue("Trace", "Clean") == 1);
68     } catch(...) {
69     }
70   } catch(RuntimeException&) {
71   }
72
73   setup(fileName, maxSize, clean);
74 }
75
76 void TraceWriter::setup(const char* fileName, const int maxSize, const bool clean)
77 throw() {
78   ssize_t r;
79
80   if(a_stream != -1) {
81     if(clean == false) {
82       string msg("\nTraces go on at: ");
83       msg += fileName;
84       msg += '\n';
85       r = write(a_stream, msg.c_str(), msg.length());
86     }
87
88     if(a_observed == true) {
89       for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++)
90         observer(ii)->handleClose(a_stream);
91     }
92
93     close(a_stream);
94     a_stream = -1;
95
96     if(clean == true) {
97       unlink(a_outputFile.c_str());
98       unlink(a_outputOldFile.c_str());
99     }
100   }
101
102   a_outputFile = fileName;
103   a_outputOldFile = a_outputFile;
104   a_outputOldFile += ".old";
105
106   if(maxSize >= (256 * 1024))
107     a_maxSize = maxSize;
108
109   char date [anna::functions::DateTimeSizeString + 7];
110   anna_strcpy(date, "- [");
111   anna_strcat(anna_strcat(date, getDate()), "]\n");
112   int stream = prepareOutput(date);
113
114   if(stream != ErrorStream) {
115     const char* aux = "\n--------------------------------------------------------------\n";
116     const char* aux2 = "- Current trace level: ";
117     r = write(stream, aux, anna_strlen(aux));
118     r = write(stream, date, anna_strlen(date));
119     r = write(stream, aux2, anna_strlen(aux2));
120     aux2 = Logger::asString(Logger::getLevel());
121     r = write(stream, aux2, anna_strlen(aux2));
122     string filesize = functions::asString("\n- Max file size : %d Kb", a_maxSize >> 10);
123     aux2 = filesize.c_str();
124     r = write(stream, aux2, anna_strlen(aux2));
125     r = write(stream, aux, anna_strlen(aux));
126   }
127 }
128
129 void TraceWriter::attach(TraceWriterObserver* observer)
130 throw() {
131   if(observer != NULL) {
132     a_observed = true;
133     a_observers.push_back(observer);
134
135     if(a_stream != -1)
136       observer->handleOpen(a_stream);
137   }
138 }
139
140 void TraceWriter::printResume()
141 throw() {
142   cout << "Traces file ..................................: " << a_outputFile << endl;
143   cout << "Backup copy  .................................: " << a_outputOldFile << endl;
144   cout << "Files size (Kbytes) ..........................: " << (a_maxSize >> 10) << endl;
145   cout << "Traces level .................................: " << Logger::asString(Logger::getLevel()) << endl << endl;
146 }
147
148 void TraceWriter::do_write(int level, const char* text, ...)
149 throw() {
150   va_list ap;
151   const char* data;
152   int size;
153   int nbytes;
154   GuardNoLog guard(a_mutex);
155   DataBlock& dataBlock(Logger::Writer::getDataBlock());
156   data = dataBlock.getData();
157   size = dataBlock.getMaxSize();
158
159   if(size == 0) {
160     dataBlock.allocate(size = 1024);
161     data = dataBlock.getData();
162   }
163
164   while(true) {
165     va_start(ap, text);
166     nbytes = vsnprintf(const_cast <char*>(data), size, text, ap);
167
168     if(nbytes >= size) {
169       dataBlock.allocate(nbytes + 1);
170       data = dataBlock.getData();
171       size = dataBlock.getMaxSize();
172       continue;
173     }
174
175     break;
176   }
177
178   va_end(ap);
179   const char* aux = Logger::asString(Logger::Level(level));
180   char date [anna::functions::DateTimeSizeString + 5];
181   date [0] = '[';
182   date [1] = 0;
183   anna_strcat(anna_strcat(date, getDate()), "] ");
184   a_stream = prepareOutput(date);
185
186   if(a_stream == ErrorStream) {
187     cerr << Logger::asString(Logger::Level(level)) << " | " << date << " | " << data << endl << endl;
188     return;
189   }
190
191   bool ok(false);
192
193   if(write(a_stream, date, anna_strlen(date)) > 0)
194     if(write(a_stream, aux, anna_strlen(aux)) > 0)
195       if(write(a_stream, " | ", 3) > 0)
196         if(write(a_stream, data, nbytes) > 0)
197           ok = (write(a_stream, "\n\n", 2) > 0);
198
199   if(ok == false && errno != EINTR)
200     perror("Cannot save traces");
201 }
202
203 const char* TraceWriter::getDate()
204 throw() {
205   const Microsecond msnow = functions::hardwareClock();
206
207   if(a_lastTime == 0 || (msnow - a_lastTime) > 1000000L) {
208     a_lastTime = msnow;
209     char date [functions::DateTimeSizeString];
210     a_date = functions::asDateTime(functions::second(), date);
211   }
212
213   return a_date.c_str();
214 }
215
216 int TraceWriter::prepareOutput(const char* date)
217 throw() {
218   int result = a_stream;
219
220   if(result == ErrorStream)
221     return result;
222
223   if(result != -1) {
224     struct stat data;
225     int r;
226     anna_signal_shield(r, stat(a_outputFile.c_str(), &data));
227
228     if(r == -1 || data.st_size > a_maxSize) {
229       if(a_observed == true) {
230         for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++)
231           observer(ii)->handleClose(a_stream);
232       }
233
234       anna_signal_shield(r, close(result));
235       rename(a_outputFile.c_str(), a_outputOldFile.c_str());
236       result = -1;
237     }
238   }
239
240   if(result == -1) {
241     anna_signal_shield(
242       result, open(a_outputFile.c_str(), O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
243     );
244
245     if(result == -1) {
246       cerr << "Cannot open the file '" << a_outputFile << "': " << strerror(errno) << endl;
247       Logger::setLevel(Logger::Error);
248       result = ErrorStream;
249     } else {
250       int r;
251       anna_signal_shield(r, fcntl(result, F_GETFL));
252
253       if(r != -1) {
254         const int opts = r | O_NONBLOCK;
255         anna_signal_shield(r, fcntl(result, F_SETFL, opts));
256       }
257     }
258
259     if(a_observed == true) {
260       for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++)
261         observer(ii)->handleOpen(result);
262     }
263   }
264
265   return result;
266 }
267