1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
17 // * Neither the name of the copyright holder 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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
46 #include <sys/types.h>
48 #include <anna/core/tracing/TraceWriter.hpp>
49 #include <anna/core/DataBlock.hpp>
50 #include <anna/core/functions.hpp>
51 #include <anna/core/util/Configuration.hpp>
52 #include <anna/core/tracing/TraceWriterObserver.hpp>
57 TraceWriter::TraceWriter() :
58 a_maxSize(DefaultMaxKBSize),
63 file = "/var/tmp/anna.process.";
64 file += functions::asString((int) getpid());
66 setup(file.c_str(), DefaultMaxKBSize, false);
69 TraceWriter::TraceWriter(const char* fileName, const int maxSize) :
70 a_maxSize(DefaultMaxKBSize),
74 setup(fileName, maxSize, false);
77 void TraceWriter::setup(const char* fileName, const Configuration& configuration)
79 int maxSize = a_maxSize;
84 maxSize = (configuration.getIntegerValue("Trace", "MaxFileSize") << 10);
89 Logger::setLevel(Logger::asLevel(configuration.getValue("Trace", "Level")));
90 } catch(Exception& ex) {
95 clean = (configuration.getIntegerValue("Trace", "Clean") == 1);
98 } catch(RuntimeException&) {
101 setup(fileName, maxSize, clean);
104 void TraceWriter::setup(const char* fileName, const int maxSize, const bool clean)
108 string msg("\nTraces go on at: ");
111 write(a_stream, msg.c_str(), msg.length());
114 if(a_observed == true) {
115 for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++)
116 observer(ii)->handleClose(a_stream);
123 unlink(a_outputFile.c_str());
124 unlink(a_outputOldFile.c_str());
128 a_outputFile = fileName;
129 a_outputOldFile = a_outputFile;
130 a_outputOldFile += ".old";
132 if(maxSize >= (256 * 1024))
135 const char* aux = Logger::asString(Logger::getLevel());
136 char date [anna::functions::DateTimeSizeString + 7];
137 anna_strcpy(date, "- [");
138 anna_strcat(anna_strcat(date, getDate()), "]\n");
139 int stream = prepareOutput(date);
141 if(stream != ErrorStream) {
142 const char* aux = "\n--------------------------------------------------------------\n";
143 const char* aux2 = "- Current trace level: ";
144 write(stream, aux, anna_strlen(aux));
145 write(stream, date, anna_strlen(date));
146 write(stream, aux2, anna_strlen(aux2));
147 aux2 = Logger::asString(Logger::getLevel());
148 write(stream, aux2, anna_strlen(aux2));
149 string filesize = functions::asString("\n- Max file size : %d Kb", a_maxSize >> 10);
150 aux2 = filesize.c_str();
151 write(stream, aux2, anna_strlen(aux2));
152 write(stream, aux, anna_strlen(aux));
156 void TraceWriter::attach(TraceWriterObserver* observer)
158 if(observer != NULL) {
160 a_observers.push_back(observer);
163 observer->handleOpen(a_stream);
167 void TraceWriter::printResume()
169 cout << "Traces file ..................................: " << a_outputFile << endl;
170 cout << "Backup copy .................................: " << a_outputOldFile << endl;
171 cout << "Files size (Kbytes) ..........................: " << (a_maxSize >> 10) << endl;
172 cout << "Traces level .................................: " << Logger::asString(Logger::getLevel()) << endl << endl;
175 void TraceWriter::do_write(int level, const char* text, ...)
181 GuardNoLog guard(a_mutex);
182 DataBlock& dataBlock(Logger::Writer::getDataBlock());
183 data = dataBlock.getData();
184 size = dataBlock.getMaxSize();
187 dataBlock.allocate(size = 1024);
188 data = dataBlock.getData();
193 nbytes = vsnprintf(const_cast <char*>(data), size, text, ap);
196 dataBlock.allocate(nbytes + 1);
197 data = dataBlock.getData();
198 size = dataBlock.getMaxSize();
206 const char* aux = Logger::asString(Logger::Level(level));
207 char date [anna::functions::DateTimeSizeString + 5];
210 anna_strcat(anna_strcat(date, getDate()), "] ");
211 a_stream = prepareOutput(date);
213 if(a_stream == ErrorStream) {
214 cerr << Logger::asString(Logger::Level(level)) << " | " << date << " | " << data << endl << endl;
220 if(write(a_stream, date, anna_strlen(date)) > 0)
221 if(write(a_stream, aux, anna_strlen(aux)) > 0)
222 if(write(a_stream, " | ", 3) > 0)
223 if(write(a_stream, data, nbytes) > 0)
224 ok = (write(a_stream, "\n\n", 2) > 0);
226 if(ok == false && errno != EINTR)
227 perror("Cannot save traces");
230 const char* TraceWriter::getDate()
232 const Microsecond msnow = functions::hardwareClock();
234 if(a_lastTime == 0 || (msnow - a_lastTime) > 1000000L) {
236 char date [functions::DateTimeSizeString];
237 a_date = functions::asDateTime(functions::second(), date);
240 return a_date.c_str();
243 int TraceWriter::prepareOutput(const char* date)
245 int result = a_stream;
247 if(result == ErrorStream)
253 anna_signal_shield(r, stat(a_outputFile.c_str(), &data));
255 if(r == -1 || data.st_size > a_maxSize) {
256 if(a_observed == true) {
257 for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++)
258 observer(ii)->handleClose(a_stream);
261 anna_signal_shield(r, close(result));
262 rename(a_outputFile.c_str(), a_outputOldFile.c_str());
269 result, open(a_outputFile.c_str(), O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
273 cerr << "Cannot open the file '" << a_outputFile << "': " << strerror(errno) << endl;
274 Logger::setLevel(Logger::Error);
275 result = ErrorStream;
278 anna_signal_shield(r, fcntl(result, F_GETFL));
281 const int opts = r | O_NONBLOCK;
282 anna_signal_shield(r, fcntl(result, F_SETFL, opts));
286 if(a_observed == true) {
287 for(observer_iterator ii = observer_begin(), maxii = observer_end(); ii != maxii; ii ++)
288 observer(ii)->handleOpen(result);