feisty meow concerns codebase  2.140
critical_events.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : critical_events *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 1989-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 #include "critical_events.h"
16 #include "program_wide_logger.h"
17 
20 #include <basis/astring.h>
21 #include <basis/functions.h>
22 #include <basis/mutex.h>
25 #include <textual/parser_bits.h>
26 #include <timely/time_stamp.h>
27 
28 #include <stdio.h>
29 #include <errno.h>
30 
31 using namespace basis;
32 using namespace structures;
33 using namespace configuration;
34 using namespace textual;
35 using namespace timely;
36 
37 const int MESSAGE_SPACE_PROVIDED = 4096;
38  // the strings should not be larger than this for diagnostic / error messages.
39 
40 namespace loggers {
41 
42 SAFE_STATIC(astring, critical_events::hidden_critical_events_dir, )
43  // define the function that holds the directory string.
44 
46 {
47  // ensure that the critical events function logs to the appropriate place.
48  return application_configuration::get_logging_directory();
49 }
50 
51 SAFE_STATIC(mutex, __critical_event_dir_lock, )
52 
53 basis::un_int critical_events::system_error()
54 {
55 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
56  return errno;
57 //#elif defined(_MSC_VER)
58 // return GetLastError();
59 #else
60  #pragma error("hmmm: no code for error number for this operating system")
61  return 0;
62 #endif
63 }
64 
65 astring critical_events::system_error_text(basis::un_int to_name)
66 {
67 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
68  return strerror(to_name);
69 /*
70 #elif defined(_MSC_VER)
71  char error_text[1000];
72  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL_POINTER, to_name,
73  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)error_text,
74  sizeof(error_text) - 1, NULL_POINTER);
75  astring to_return = error_text;
76  // trim off the ridiculous carriage return they add.
77  while ( (to_return[to_return.end()] == '\r')
78  || (to_return[to_return.end()] == '\n') )
79  to_return.zap(to_return.end(), to_return.end());
80  return to_return;
81 */
82 #else
83  #pragma error("hmmm: no code for error text for this operating system")
84  return "";
85 #endif
86 }
87 
88 astring critical_events::critical_events_directory()
89 {
90  static bool initted = false;
91  if (!initted) {
92  auto_synchronizer l(__critical_event_dir_lock());
93  if (!initted) {
94  set_critical_events_directory(default_critical_location());
95  initted = true;
96  }
97  }
98  return hidden_critical_events_dir();
99 }
100 
101 void critical_events::set_critical_events_directory(const astring &directory)
102 { hidden_critical_events_dir() = directory; }
103 
104 void critical_events::write_to_critical_events(const char *to_write)
105 {
106  astring filename = critical_events_directory();
107  filename += "/runtime_issues.log";
108  FILE *errfile = fopen(filename.s(), "ab");
109  if (errfile) {
110  astring app_name = application_configuration::application_name();
111  int indy = app_name.find('/', app_name.end(), true);
112  if (non_negative(indy)) app_name.zap(0, indy);
113  indy = app_name.find('\\', app_name.end(), true);
114  if (non_negative(indy)) app_name.zap(0, indy);
115  fprintf(errfile, "%s [%s]:%s", time_stamp::notarize(true).s(),
116  app_name.s(), parser_bits::platform_eol_to_chars());
117  fprintf(errfile, "%s%s", to_write, parser_bits::platform_eol_to_chars());
118  fclose(errfile);
119  }
120 }
121 
122 void critical_events::write_to_console(const char *guards_message_space)
123 { fprintf(stderr, "%s", (char *)guards_message_space); fflush(stderr); }
124 
125 void critical_events::alert_message(const char *info, const char *title)
126 {
127  astring to_print;
128  if (strlen(title)) {
129  const char border = '=';
130  to_print += astring(border, int(strlen(title)) + 4);
131  to_print += parser_bits::platform_eol_to_chars();
132  to_print += border;
133  to_print += ' ';
134  to_print += title;
135  to_print += ' ';
136  to_print += border;
137  to_print += parser_bits::platform_eol_to_chars();
138  to_print += astring(border, int(strlen(title)) + 4);
139  to_print += parser_bits::platform_eol_to_chars();
140  }
141 
142  to_print += info;
143  program_wide_logger::get().log(to_print, ALWAYS_PRINT);
144  fflush(NULL_POINTER); // flush all output streams.
145 }
146 
147 void critical_events::alert_message(const astring &info) { alert_message(info.s()); }
148 
149 void critical_events::alert_message(const astring &info, const astring &title)
150 { alert_message(info.s(), title.s()); }
151 
152 void critical_events::make_error_message(const char *file, int line,
153  const char *error_class, const char *error_function,
154  const char *info, char *guards_message_space)
155 {
156  strcpy(guards_message_space, "\nProblem reported for \"");
157 //hmmm: only copy N chars of each into the space.
158 // say 40 for class/function each, then the space - consumed for the
159 // info. get strlen for real on the class and function name to know
160 // actual size for that computation.
161  strcat(guards_message_space, error_class);
162  strcat(guards_message_space, "::");
163  strcat(guards_message_space, error_function);
164  strcat(guards_message_space, "\"\n(invoked at line ");
165  char line_num[20];
166  sprintf(line_num, "%d", line);
167  strcat(guards_message_space, line_num);
168  strcat(guards_message_space, " in ");
169  strcat(guards_message_space, file);
170  strcat(guards_message_space, " at ");
171  strcat(guards_message_space, time_stamp::notarize(false).s());
172  strcat(guards_message_space, ")\n");
173  strcat(guards_message_space, info);
174  strcat(guards_message_space, "\n\n\n");
175 }
176 
177 void critical_events::FL_deadly_error(const char *file, int line, const char *error_class,
178  const char *error_function, const char *info)
179 {
180  FL_continuable_error(file, line, error_class, error_function, info,
181  "Deadly Error Information");
183  throw "deadly_error";
184  // abort() is not as good an approach as throwing an exception. aborts are
185  // harder to track with some compilers, but all should be able to trap an
186  // exception.
187 }
188 
189 void critical_events::FL_deadly_error(const astring &file, int line,
190  const astring &error_class, const astring &error_function,
191  const astring &info)
192 {
193  FL_deadly_error(file.s(), line, error_class.s(), error_function.s(),
194  info.s());
195 }
196 
197 void critical_events::FL_continuable_error_real(const char *file, int line,
198  const char *error_class, const char *error_function, const char *info,
199  const char *title)
200 {
201  char guards_message_space[MESSAGE_SPACE_PROVIDED];
202  // this routine could still fail, if the call stack is already jammed
203  // against its barrier. but if that's the case, even the simple function
204  // call might fail. in any case, we cannot deal with a stack overflow
205  // type error using this function. but we would rather deal with that
206  // than make the space static since that would cause corruption when
207  // two threads wrote errors at the same time.
208  make_error_message(file, line, error_class, error_function, info,
209  guards_message_space);
210  alert_message(guards_message_space, title);
211 }
212 
213 void critical_events::FL_continuable_error(const char *file, int line,
214  const char *error_class, const char *error_function, const char *info,
215  const char *title)
216 {
217  FL_continuable_error_real(file, line, error_class, error_function, info, title);
218 }
219 
220 void critical_events::FL_continuable_error(const astring &file, int line,
221  const astring &error_class, const astring &error_function,
222  const astring &info, const astring &title)
223 {
224  FL_continuable_error_real(file.s(), line, error_class.s(),
225  error_function.s(), info.s(), title.s());
226 }
227 
228 void critical_events::FL_non_continuable_error(const char *file, int line,
229  const char *error_class, const char *error_function, const char *info,
230  const char *title)
231 {
232  FL_continuable_error_real(file, line, error_class, error_function, info,
233  title);
234  exit(EXIT_FAILURE); // let the outside world know that there was a problem.
235 }
236 
237 void critical_events::FL_non_continuable_error(const astring &file, int line,
238  const astring &error_class, const astring &error_function,
239  const astring &info, const astring &title)
240 {
241  FL_continuable_error_real(file.s(), line, error_class.s(),
242  error_function.s(), info.s(), title.s());
243  exit(EXIT_FAILURE); // let the outside world know that there was a problem.
244 }
245 
246 void critical_events::FL_console_error(const char *file, int line, const char *error_class,
247  const char *error_function, const char *info)
248 {
249  char guards_message_space[MESSAGE_SPACE_PROVIDED];
250  make_error_message(file, line, error_class, error_function, info,
251  guards_message_space);
252  write_to_console(guards_message_space);
253 }
254 
255 void critical_events::FL_out_of_memory_now(const char *file, int line,
256  const char *the_class_name, const char *the_func)
257 {
258  FL_non_continuable_error(file, line, the_class_name, the_func,
259  "Program stopped due to memory allocation failure.",
260  "Out of Memory Now");
261 }
262 
263 void critical_events::implement_bounds_halt(const char *the_class_name, const char *the_func,
264  const char *value, const char *low, const char *high,
265  const char *error_addition)
266 {
267  char message[400];
268  strcpy(message, "bounds error caught");
269  strcat(message, error_addition);
270  strcat(message, ":\r\n");
271  strcat(message, value);
272  strcat(message, " is not between ");
273  strcat(message, low);
274  strcat(message, " and ");
275  strcat(message, high);
276 #ifdef ERRORS_ARE_FATAL
277  deadly_error(the_class_name, the_func, message);
278 #else
279  continuable_error(the_class_name, the_func, message);
280 #endif
281 }
282 
283 } //namespace.
284 
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
Definition: astring.cpp:521
int end() const
returns the index of the last (non-null) character in the string.
Definition: astring.h:86
int find(char to_find, int position=0, bool reverse=false) const
Locates "to_find" in "this".
Definition: astring.cpp:574
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition: mutex.h:113
Provides a means of logging events for runtime problems.
const int MESSAGE_SPACE_PROVIDED
#define continuable_error(c, f, i)
#define deadly_error(c, f, i)
#define CAUSE_BREAKPOINT
This macro wraps the notion of stopping in the debugger.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
bool non_negative(const type &a)
non_negative returns true if "a" is greater than or equal to zero.
Definition: functions.h:45
unsigned int un_int
Abbreviated name for unsigned integers.
Definition: definitions.h:62
A logger that sends to the console screen using the standard output device.
astring default_critical_location()
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
#include <time.h>
Definition: earth_time.cpp:37
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
Aids in achievement of platform independence.