/* -*- LPC -*- */
/*
* $Id: logging.c,v 1.13 2002/05/05 17:55:54 wodan Exp $
*/
#include <type.h>
#include <runtime_config.h>
/*
* returns the owner of ob (for error logging)
* all calls to this should call get_prg_name()
*/
string get_wiz_name(mixed file) {
if (!previous_object())
return "root";
if (objectp(file))
file = file_name(file);
file = explode(file, "/") - ({ "" });
if (file[0] == "w") {
if (file_size("/w/" + file[1]) != -2) {
return "root";
} else {
return file[1];
}
}
if (file[0] == "d") {
return "dom";
}
return "root";
} /* get_wiz_name() */
string get_dom_name(mixed file) {
if (objectp(file))
file = file_name(file);
file = explode(file, "/") - ({ "" });
if (file[0] == "d" && sizeof(file) >= 2)
return file[1];
} /* get_dom_name() */
/*
* return the owner of file (for error logging)
*/
string get_prg_name(mixed file) {
if (objectp(file))
file = file_name(file);
file = explode(file, "/") - ({ "" });
if (file[0] == "w")
return file[1];
return "root";
} /* get_prg_name() */
int different(string fn, string pr) {
sscanf(fn, "%s#%*d", fn);
fn += ".c";
return (fn != pr) && (fn != ("/" + pr));
}
string trace_line(object obj, string prog, string file, int line) {
string ret;
string objfn = obj ? file_name(obj) : "<none>";
ret = objfn;
if (different(objfn, prog))
ret += sprintf(" (%s)", prog);
if (file != prog)
ret += sprintf(" in %s:%d\n", file, line);
else
ret += sprintf(" at line %d\n", line);
return ret;
}
string printable_arg(mixed arg) {
switch (typeof(arg)) {
case ARRAY:
case MAPPING:
case CLASS:
case STRING:
if((strlen(typeof(arg)) + strlen(save_variable(arg)) + 4) < __MAX_STRING_LENGTH__)
return "(" + typeof(arg) + ") " + save_variable(arg);
else
return sprintf("(%s) <too large>", typeof(arg));
default:
return sprintf("(%s) %O", typeof(arg), arg);
}
}
string trace_args(mixed *args) {
string *tmp;
if (!sizeof(args))
return " (void)";
tmp = map(args, (: printable_arg($1) :));
return "\n(\n "+implode(tmp, ",\n ")+"\n)";
}
string trace_locals(mixed *args) {
string *tmp;
if (!sizeof(args))
return " none.";
tmp = map(args, (: printable_arg($1) :));
return "\n " + implode(tmp, ",\n ");
}
varargs string standard_trace(mapping mp, int flag) {
string ret;
mapping *trace;
int i, n;
ret = mp["error"] + "Object: " +
trace_line(mp["object"], mp["program"], mp["file"], mp["line"]);
ret += "Arguments were:" + trace_args(mp["arguments"]) +
"\nLocals were:" + trace_locals(mp["locals"]) + "\n";
ret += "\n\n";
trace = mp["trace"];
n = sizeof(trace);
for (i=0; i<n; i++) {
/* if( flag ) ret += sprintf("#%d: ", i); */
ret += sprintf("(%d) '%s' in %s", i + 1, trace[i]["function"],
trace_line(trace[i]["object"], trace[i]["program"],
trace[i]["file"], trace[i]["line"]));
if (!flag && (strlen(ret) + strlen(trace_args(trace[i]["arguments"])) +
strlen(trace_locals(trace[i]["locals"])) +
20) < __MAX_STRING_LENGTH__) {
ret += "Arguments were:" + trace_args(trace[i]["arguments"]) +
"\nLocals were:" + trace_locals(trace[i]["locals"]) + "\n";
}
}
return ret;
}
#define MAX_SIZE 50000
void error_handler(mapping error, int caught) {
string file, ret, path, name, obname;
object ob;
ret = "--------------------\n"+ctime(time()) + ": " + standard_trace(error);
if (caught) {
file = "catch";
} else {
file = "runtime";
}
sscanf(error["error"], "%*sError in loading object '%s'", obname);
if (!obname) {
ob = error["object"];
if (!ob) {
obname = error["program"];
} else {
obname = file_name(ob);
}
}
name = get_wiz_name(obname);
switch (name) {
case "root":
path = "/log/" + file;
break;
case "dom":
//
// Special test to try and trace the player housing errors.
//
if (obname[0..17] == "/d/am/short/flats/") {
path = "/d/am/short/flats/" + file;
} else {
switch (obname[0..9]) {
case "/d/am/elm/" :
case "/d/am/lame" :
path = "/d/am/short/flats/" + file;
//path = "/d/"+implode(explode(obname, "/")[0..2], "/") + file;
break;
default :
break;
}
}
path = "/d/"+get_dom_name(obname)+"/"+file;
break;
default:
path = "/w/"+name+"/"+file;
tell_creator(name, "A runtime error occured in the file %O"
", logged to %s.\n", obname, path);
}
//
// Check to see if the autoload stuff is involved in this error.
//
if (member_array("init_dynamic_arg", call_stack(2)) != -1 ||
member_array("query_dynamic_auto_load", call_stack(2)) != -1) {
path = "/d/admin/log/auto_" + file;
}
if (file_size(path) > MAX_SIZE) {
unguarded((: rm, path+".old" :));
unguarded((: rename, path, path+".old" :));
}
unguarded((: write_file, path, ret :));
if (this_player(1) && find_object("/secure/simul_efun")) {
this_player(1)->set_last_error(error);
if (!caught) {
if (this_player(1)->query_creator()) {
tell_object(this_player(1), error["error"]+
"Object: "+trace_line(error["object"], error["program"],
error["file"], error["line"])+
"\nTrace written to "+ path +"\n");
} else {
tell_object(this_player(1),
"A runtime error occurred.\nPlease use "
"the \"bug\" command to report it, "
"describing what you tried to do when it happened.\n");
}
}
}
}
/*
* Write an error message into a log file. The error occurred in the object
* 'file', giving the error message 'message'.
*/
void log_error(string file, string message) {
string name, efile, epath, colour;
if (sscanf(message, "%*sWarning:%*s") == 2) {
if(sscanf(message, "%*sTrying to put%*s") == 2) {
efile = "type-error";
colour = "%^RED%^";
} else {
efile = "warnings";
colour = "%^CYAN%^";
}
} else {
efile = "error-log";
colour = "%^RED%^";
}
if (this_player(1) && this_player(1)->query_creator()) {
tell_object(this_player(1), colour+message+"%^RESET%^");
}
name = get_wiz_name(file);
switch (name) {
case "root":
epath = "/log/" + efile;
break;
case "dom":
epath = "/d/"+get_dom_name(file)+"/"+efile;
break;
default:
epath = "/w/"+name+"/"+efile;
break;
}
if (file_size(epath) > MAX_SIZE) {
unguarded((: rm, epath+".old" :));
unguarded((: rename, epath, epath+".old" :));
}
unguarded((: write_file, epath, message :));
} /* log_error() */
void do_log(string person, string text) {
if (file_name(previous_object()) != "/std/smart_log")
return;
if (file_size("/w/"+person) != -2)
return;
unguarded((: rm, "/w/"+person+"/"+PLAYER_ERROR_LOG :));
unguarded((: write_file, "/w/"+person+"/"+PLAYER_ERROR_LOG, text :));
} /* do_log() */
void forward_error(string file, string text) {
if (!((file_name(previous_object()) == "/secure/cmds/creator/errors") ||
(file_name(previous_object()) == "/www/secure/errors")))
return;
unguarded((: write_file, file, text :));
} /* forward_error() */