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

Archive Download this file

Branches

Tags

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