monotone

monotone Mtn Source Tree

Root/sanity.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <stdio.h>
7#include <stdarg.h>
8
9#include <algorithm>
10#include <iterator>
11#include <iostream>
12#include <fstream>
13#include <string>
14#include <vector>
15#include <sstream>
16
17#include <boost/lexical_cast.hpp>
18
19#include "constants.hh"
20#include "platform.hh"
21#include "sanity.hh"
22#include "transforms.hh"
23#include "ui.hh"
24
25using namespace std;
26using boost::format;
27
28// debugging / logging system
29
30sanity global_sanity;
31
32sanity::sanity() :
33 debug(false), quiet(false), relaxed(false), logbuf(0xffff), already_dumping(false)
34{
35 std::string flavour;
36 get_system_flavour(flavour);
37 L(F("started up on %s\n") % flavour);
38}
39
40sanity::~sanity()
41{}
42
43void
44sanity::dump_buffer()
45{
46 if (!filename.empty())
47 {
48 ofstream out(filename.as_external().c_str());
49 if (out)
50 {
51 copy(logbuf.begin(), logbuf.end(), ostream_iterator<char>(out));
52 copy(gasp_dump.begin(), gasp_dump.end(), ostream_iterator<char>(out));
53 ui.inform((F("wrote debugging log to %s") % filename).str());
54 }
55 else
56 ui.inform((F("failed to write debugging log to %s") % filename).str());
57 }
58 else
59 ui.inform("discarding debug log (maybe you want --debug or --dump?)");
60}
61
62void
63sanity::set_debug()
64{
65 quiet = false;
66 debug = true;
67
68 // it is possible that some pre-setting-of-debug data
69 // accumulated in the log buffer (during earlier option processing)
70 // so we will dump it now
71 ostringstream oss;
72 vector<string> lines;
73 copy(logbuf.begin(), logbuf.end(), ostream_iterator<char>(oss));
74 split_into_lines(oss.str(), lines);
75 for (vector<string>::const_iterator i = lines.begin(); i != lines.end(); ++i)
76 ui.inform((*i) + "\n");
77}
78
79void
80sanity::set_brief()
81{
82 brief = true;
83}
84
85void
86sanity::set_quiet()
87{
88 debug = false;
89 quiet = true;
90}
91
92void
93sanity::set_relaxed(bool rel)
94{
95 relaxed = rel;
96}
97
98string
99sanity::do_format(format const & fmt, char const * file, int line)
100{
101 try
102 {
103 return fmt.str();
104 }
105 catch (std::exception & e)
106 {
107 ui.inform(F("fatal: formatter failed on %s:%d: %s")
108% file
109% line
110% e.what());
111 throw;
112 }
113}
114
115
116void
117sanity::log(format const & fmt,
118 char const * file, int line)
119{
120 string str = do_format(fmt, file, line);
121
122 if (str.size() > constants::log_line_sz)
123 {
124 str.resize(constants::log_line_sz);
125 if (str.at(str.size() - 1) != '\n')
126 str.at(str.size() - 1) = '\n';
127 }
128 copy(str.begin(), str.end(), back_inserter(logbuf));
129 if (str[str.size() - 1] != '\n')
130 logbuf.push_back('\n');
131 if (debug)
132 ui.inform(str);
133}
134
135void
136sanity::progress(format const & fmt,
137 char const * file, int line)
138{
139 string str = do_format(fmt, file, line);
140
141 if (str.size() > constants::log_line_sz)
142 {
143 str.resize(constants::log_line_sz);
144 if (str.at(str.size() - 1) != '\n')
145 str.at(str.size() - 1) = '\n';
146 }
147 copy(str.begin(), str.end(), back_inserter(logbuf));
148 if (str[str.size() - 1] != '\n')
149 logbuf.push_back('\n');
150 if (! quiet)
151 ui.inform(str);
152}
153
154void
155sanity::warning(format const & fmt,
156 char const * file, int line)
157{
158 string str = do_format(fmt, file, line);
159
160 if (str.size() > constants::log_line_sz)
161 {
162 str.resize(constants::log_line_sz);
163 if (str.at(str.size() - 1) != '\n')
164 str.at(str.size() - 1) = '\n';
165 }
166 string str2 = "warning: " + str;
167 copy(str2.begin(), str2.end(), back_inserter(logbuf));
168 if (str[str.size() - 1] != '\n')
169 logbuf.push_back('\n');
170 if (! quiet)
171 ui.warn(str);
172}
173
174void
175sanity::naughty_failure(string const & expr, format const & explain,
176 string const & file, int line)
177{
178 string message;
179 log(format("%s:%d: usage constraint '%s' violated\n") % file % line % expr,
180 file.c_str(), line);
181 prefix_lines_with(_("misuse: "), explain.str(), message);
182 throw informative_failure(message);
183}
184
185void
186sanity::error_failure(string const & expr, format const & explain,
187 string const & file, int line)
188{
189 string message;
190 log(format("%s:%d: detected error '%s' violated\n") % file % line % expr,
191 file.c_str(), line);
192 prefix_lines_with(_("error: "), explain.str(), message);
193 throw informative_failure(message);
194}
195
196void
197sanity::invariant_failure(string const & expr,
198 string const & file, int line)
199{
200 format fmt =
201 format("%s:%d: invariant '%s' violated\n")
202 % file % line % expr;
203 log(fmt, file.c_str(), line);
204 gasp();
205 throw logic_error(fmt.str());
206}
207
208void
209sanity::index_failure(string const & vec_expr,
210 string const & idx_expr,
211 unsigned long sz,
212 unsigned long idx,
213 string const & file, int line)
214{
215 format fmt =
216 format("%s:%d: index '%s' = %d overflowed vector '%s' with size %d\n")
217 % file % line % idx_expr % idx % vec_expr % sz;
218 log(fmt, file.c_str(), line);
219 gasp();
220 throw logic_error(fmt.str());
221}
222
223// Last gasp dumps
224
225void
226sanity::gasp()
227{
228 if (already_dumping)
229 {
230 L(F("ignoring request to give last gasp; already in process of dumping\n"));
231 return;
232 }
233 already_dumping = true;
234 L(F("saving current work set: %i items") % musings.size());
235 std::ostringstream out;
236 out << F("Current work set: %i items\n") % musings.size();
237 for (std::vector<MusingI const *>::const_iterator
238 i = musings.begin(); i != musings.end(); ++i)
239 {
240 std::string tmp;
241 try
242 {
243 (*i)->gasp(tmp);
244 out << tmp;
245 }
246 catch (logic_error)
247 {
248 out << tmp;
249 out << "<caught logic_error>\n";
250 L(F("ignoring error trigged by saving work set to debug log"));
251 }
252 catch (informative_failure)
253 {
254 out << tmp;
255 out << "<caught informative_failure>\n";
256 L(F("ignoring error trigged by saving work set to debug log"));
257 }
258 }
259 gasp_dump = out.str();
260 L(F("finished saving work set"));
261 if (debug)
262 {
263 ui.inform("contents of work set:");
264 ui.inform(gasp_dump);
265 }
266 already_dumping = false;
267}
268
269MusingI::MusingI()
270{
271 if (!global_sanity.already_dumping)
272 global_sanity.musings.push_back(this);
273}
274
275MusingI::~MusingI()
276{
277 if (!global_sanity.already_dumping)
278 {
279 I(global_sanity.musings.back() == this);
280 global_sanity.musings.pop_back();
281 }
282}
283
284void
285dump(std::string const & obj, std::string & out)
286{
287 out = obj;
288}
289
290
291void MusingBase::gasp(const std::string & objstr, std::string & out) const
292{
293 out = (boost::format("----- begin '%s' (in %s, at %s:%d)\n"
294 "%s"
295 "----- end '%s' (in %s, at %s:%d)\n")
296 % name % func % file % line
297 % objstr
298 % name % func % file % line
299 ).str();
300}
301
302
303boost::format F(const char * str)
304{
305 return boost::format(gettext(str), get_user_locale());
306}
307
308
309boost::format FP(const char * str1, const char * strn, unsigned long count)
310{
311 return boost::format(ngettext(str1, strn, count), get_user_locale());
312}
313

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status