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
21#include <basis/astring.h>
22#include <basis/functions.h>
23#include <basis/mutex.h>
26#include <textual/parser_bits.h>
27#include <timely/time_stamp.h>
28
29#include <stdio.h>
30#include <errno.h>
31
32using namespace application;
33using namespace basis;
34using namespace structures;
35using namespace configuration;
36using namespace textual;
37using namespace timely;
38
39const int MESSAGE_SPACE_PROVIDED = 4096;
40 // the strings should not be larger than this for diagnostic / error messages.
41
42namespace loggers {
43
44SAFE_STATIC(astring, critical_events::hidden_critical_events_dir, )
45 // define the function that holds the directory string.
46
48{
49 // ensure that the critical events function logs to the appropriate place.
51}
52
53SAFE_STATIC(mutex, __critical_event_dir_lock, )
54
56{
57#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
58 return errno;
59//#elif defined(_MSC_VER)
60// return GetLastError();
61#else
62 #pragma error("hmmm: no code for error number for this operating system")
63 return 0;
64#endif
65}
66
68{
69#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
70 return strerror(to_name);
71/*
72#elif defined(_MSC_VER)
73 char error_text[1000];
74 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL_POINTER, to_name,
75 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)error_text,
76 sizeof(error_text) - 1, NULL_POINTER);
77 astring to_return = error_text;
78 // trim off the ridiculous carriage return they add.
79 while ( (to_return[to_return.end()] == '\r')
80 || (to_return[to_return.end()] == '\n') )
81 to_return.zap(to_return.end(), to_return.end());
82 return to_return;
83*/
84#else
85 #pragma error("hmmm: no code for error text for this operating system")
86 return "";
87#endif
88}
89
91{
92 static bool initted = false;
93 if (!initted) {
94 auto_synchronizer l(__critical_event_dir_lock());
95 if (!initted) {
97 initted = true;
98 }
99 }
100 return hidden_critical_events_dir();
101}
102
104{ hidden_critical_events_dir() = directory; }
105
107{
109 filename += "/runtime_issues.log";
110 FILE *errfile = fopen(filename.s(), "ab");
111 if (errfile) {
113 int indy = app_name.find('/', app_name.end(), true);
114 if (non_negative(indy)) app_name.zap(0, indy);
115 indy = app_name.find('\\', app_name.end(), true);
116 if (non_negative(indy)) app_name.zap(0, indy);
117 fprintf(errfile, "%s [%s]:%s", time_stamp::notarize(true).s(),
119 fprintf(errfile, "%s%s", to_write, parser_bits::platform_eol_to_chars());
120 fclose(errfile);
121 }
122}
123
124void critical_events::write_to_console(const char *guards_message_space)
125{ fprintf(stderr, "%s", (char *)guards_message_space); fflush(stderr); }
126
127void critical_events::alert_message(const char *info, const char *title)
128{
129 astring to_print;
130 if (strlen(title)) {
131 const char border = '=';
132 to_print += astring(border, int(strlen(title)) + 4);
134 to_print += border;
135 to_print += ' ';
136 to_print += title;
137 to_print += ' ';
138 to_print += border;
140 to_print += astring(border, int(strlen(title)) + 4);
142 }
143
144 to_print += info;
145 program_wide_logger::get().log(to_print, ALWAYS_PRINT);
146 fflush(NULL_POINTER); // flush all output streams.
147}
148
150
151void critical_events::alert_message(const astring &info, const astring &title)
152{ alert_message(info.s(), title.s()); }
153
154void critical_events::make_error_message(const char *file, int line,
155 const char *error_class, const char *error_function,
156 const char *info, char *guards_message_space)
157{
158 strcpy(guards_message_space, "\nProblem reported for \"");
159/*hmmm: only copy N chars of each into the space.
160 say 40 for class/function each, then the space - consumed for the
161 info. get strlen for real on the class and function name to know
162 actual size for that computation.
163*/
164 strcat(guards_message_space, error_class);
165 strcat(guards_message_space, "::");
166 strcat(guards_message_space, error_function);
167 strcat(guards_message_space, "\"\n(invoked at line ");
168 char line_num[20];
169 sprintf(line_num, "%d", line);
170 strcat(guards_message_space, line_num);
171 strcat(guards_message_space, " in ");
172 strcat(guards_message_space, file);
173 strcat(guards_message_space, " at ");
174 strcat(guards_message_space, time_stamp::notarize(false).s());
175 strcat(guards_message_space, ")\n");
176 strcat(guards_message_space, info);
177 strcat(guards_message_space, "\n\n\n");
178}
179
180void critical_events::FL_deadly_error(const char *file, int line, const char *error_class,
181 const char *error_function, const char *info)
182{
183 FL_continuable_error(file, line, error_class, error_function, info,
184 "Deadly Error Information");
186 throw "deadly_error";
187 /* why we use an exception here--abort() is not as good an approach as
188 throwing an exception. aborts are harder to track with some compilers,
189 but all should be able to trap an exception. if not, get a new compiler,
190 please. */
191}
192
193void critical_events::FL_deadly_error(const astring &file, int line,
194 const astring &error_class, const astring &error_function,
195 const astring &info)
196{
197 FL_deadly_error(file.s(), line, error_class.s(), error_function.s(),
198 info.s());
199}
200
201void critical_events::FL_continuable_error_real(const char *file, int line,
202 const char *error_class, const char *error_function, const char *info,
203 const char *title)
204{
205 char guards_message_space[MESSAGE_SPACE_PROVIDED];
206 /* this routine could still fail, if the call stack is already jammed
207 against its barrier. but if that's the case, even the simple function
208 call might fail. in any case, we cannot deal with a stack overflow
209 type error using this function. but we would rather deal with that
210 than make the space static since that would cause corruption when
211 two threads wrote errors at the same time. */
212 make_error_message(file, line, error_class, error_function, info,
213 guards_message_space);
214 alert_message(guards_message_space, title);
215#ifdef ENABLE_CALLSTACK_TRACKING
216 char *stack_trace = thread_wide_stack_trace().full_trace();
217 alert_message(stack_trace, "current stack trace");
218 // super important to free the space again.
219 free(stack_trace);
220#endif
221}
222
223void critical_events::FL_continuable_error(const char *file, int line,
224 const char *error_class, const char *error_function, const char *info,
225 const char *title)
226{
227 FL_continuable_error_real(file, line, error_class, error_function, info, title);
228}
229
231 const astring &error_class, const astring &error_function,
232 const astring &info, const astring &title)
233{
234 FL_continuable_error_real(file.s(), line, error_class.s(),
235 error_function.s(), info.s(), title.s());
236}
237
238void critical_events::FL_non_continuable_error(const char *file, int line,
239 const char *error_class, const char *error_function, const char *info,
240 const char *title)
241{
242 FL_continuable_error_real(file, line, error_class, error_function, info,
243 title);
244 exit(EXIT_FAILURE); // let the outside world know that there was a problem.
245}
246
248 const astring &error_class, const astring &error_function,
249 const astring &info, const astring &title)
250{
251 FL_continuable_error_real(file.s(), line, error_class.s(),
252 error_function.s(), info.s(), title.s());
253 exit(EXIT_FAILURE); // let the outside world know that there was a problem.
254}
255
256void critical_events::FL_console_error(const char *file, int line, const char *error_class,
257 const char *error_function, const char *info)
258{
259 char guards_message_space[MESSAGE_SPACE_PROVIDED];
260 make_error_message(file, line, error_class, error_function, info,
261 guards_message_space);
262 write_to_console(guards_message_space);
263}
264
265void critical_events::FL_out_of_memory_now(const char *file, int line,
266 const char *the_class_name, const char *the_func)
267{
268 FL_non_continuable_error(file, line, the_class_name, the_func,
269 "Program stopped due to memory allocation failure.",
270 "Out of Memory Now");
271}
272
273void critical_events::implement_bounds_halt(const char *the_class_name, const char *the_func,
274 const char *value, const char *low, const char *high,
275 const char *error_addition)
276{
277 char message[400];
278 strcpy(message, "bounds error caught");
279 strcat(message, error_addition);
280 strcat(message, ":\r\n");
281 strcat(message, value);
282 strcat(message, " is not between ");
283 strcat(message, low);
284 strcat(message, " and ");
285 strcat(message, high);
286#ifdef ERRORS_ARE_FATAL
287 deadly_error(the_class_name, the_func, message);
288#else
289 continuable_error(the_class_name, the_func, message);
290#endif
291}
292
293} //namespace.
294
char * full_trace() const
provides the current stack trace in a newly malloc'd string.
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:524
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:577
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition mutex.h:113
virtual outcome log(const base_string &info, int filter)=0
writes the information in "info" to the logger using the "filter".
static basis::astring get_logging_directory()
< retrieves the core binary directory location from paths.ini.
static basis::astring application_name()
returns the full name of the current application.
Provides a means of logging events for runtime problems.
static void FL_console_error(const char *file, int line, const char *error_class, const char *error_function, const char *info)
Prints out an error message to the standard error file stream.
static void FL_non_continuable_error(const char *file, int line, const char *classname, const char *function_name, const char *info, const char *title)
Shows the same information as continuable_error, but causes an exit.
static void implement_bounds_halt(const char *the_class_name, const char *func, const char *value, const char *low, const char *high, const char *error_addition)
Provides the real implementation of bounds_halt to save code space.
static void set_critical_events_directory(const basis::astring &directory)
sets the internal location where the critical events will be logged.
static void FL_out_of_memory_now(const char *file, int line, const char *classname, const char *function_name)
Causes the program to exit due to a memory allocation failure.
static void write_to_critical_events(const char *message)
sends the "message" to the critical events log file.
static basis::astring critical_events_directory()
returns the current location where critical events are written.
static basis::astring system_error_text(basis::un_int error_to_show)
returns the OS's string form of the "error_to_show".
static void FL_deadly_error(const char *file, int line, const char *classname, const char *function_name, const char *info)
Prints out an error message and then exits the program.
static void make_error_message(const char *file, int line, const char *error_class, const char *error_function, const char *info, char *guards_message_space)
Used to build our particular type of error message.
static void alert_message(const char *info, const char *title="Alert Message")
shows the message in "info", with an optional "title" on the message.
static void write_to_console(const char *message)
Prints out a message to the standard error file stream.
static void FL_continuable_error(const char *file, int line, const char *classname, const char *function_name, const char *info, const char *title)
Describes an error like deadly_error, but does not exit the program.
static loggers::standard_log_base & get()
Provided by the startup code within each application for logging.
static const char * platform_eol_to_chars()
provides the characters that make up this platform's line ending.
static basis::astring notarize(bool add_space=true)
a useful method for getting a textual version of the time "right now".
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
Implements an application lock to ensure only one is running at once.
callstack_tracker & thread_wide_stack_trace()
the provider of thread-wide (single instance per thread) callstack_trackers.
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>
#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.