void gjs_error_reporter(JSContext *context, const char *message, JSErrorReport *report) { const char *warning; if (gjs_environment_variable_is_set("GJS_ABORT_ON_OOM") && report->flags == JSREPORT_ERROR && report->errorNumber == JSMSG_OUT_OF_MEMORY) { g_error("GJS ran out of memory at %s: %i.", report->filename, report->lineno); } if ((report->flags & JSREPORT_WARNING) != 0) { /* We manually insert "WARNING" into the output instead of * having GJS_DEBUG_WARNING because it's convenient to * search for 'JS ERROR' to find all problems */ warning = "WARNING: "; /* suppress bogus warnings. See mozilla/js/src/js.msg */ switch (report->errorNumber) { /* 162, JSMSG_UNDEFINED_PROP: warns every time a lazy property * is resolved, since the property starts out * undefined. When this is a real bug it should usually * fail somewhere else anyhow. */ case 162: return; } } else { warning = "REPORTED: "; } gjs_debug(GJS_DEBUG_ERROR, "%s'%s'", warning, message); gjs_debug(GJS_DEBUG_ERROR, "%sfile '%s' line %u exception %d number %d", warning, report->filename, report->lineno, (report->flags & JSREPORT_EXCEPTION) != 0, report->errorNumber); }
void gjs_debug(GjsDebugTopic topic, const char *format, ...) { static FILE *logfp = NULL; static gboolean debug_log_enabled = FALSE; static gboolean strace_timestamps = FALSE; static gboolean checked_for_timestamp = FALSE; static gboolean print_timestamp = FALSE; static GTimer *timer = NULL; const char *prefix; va_list args; char *s; if (!checked_for_timestamp) { print_timestamp = gjs_environment_variable_is_set("GJS_DEBUG_TIMESTAMP"); checked_for_timestamp = TRUE; } if (print_timestamp && !timer) { timer = g_timer_new(); } if (logfp == NULL) { const char *debug_output = g_getenv("GJS_DEBUG_OUTPUT"); if (debug_output != NULL && strcmp(debug_output, "stderr") == 0) { debug_log_enabled = TRUE; } else if (debug_output != NULL) { const char *log_file; char *free_me; char *c; /* Allow debug-%u.log for per-pid logfiles as otherwise log * messages from multiple processes can overwrite each other. * * (printf below should be safe as we check '%u' is the only format * string) */ c = strchr((char *) debug_output, '%'); if (c && c[1] == 'u' && !strchr(c+1, '%')) { free_me = g_strdup_printf(debug_output, (guint)getpid()); log_file = free_me; } else { log_file = debug_output; free_me = NULL; } /* avoid truncating in case we're using shared logfile */ logfp = fopen(log_file, "a"); if (!logfp) fprintf(stderr, "Failed to open log file `%s': %s\n", log_file, g_strerror(errno)); g_free(free_me); debug_log_enabled = TRUE; } if (logfp == NULL) logfp = stderr; strace_timestamps = gjs_environment_variable_is_set("GJS_STRACE_TIMESTAMPS"); } /* only strace timestamps if debug * log wasn't specifically switched on */ if (!debug_log_enabled && topic != GJS_DEBUG_STRACE_TIMESTAMP) return; switch (topic) { case GJS_DEBUG_STRACE_TIMESTAMP: /* return early if strace timestamps are disabled, avoiding * printf format overhead and so forth. */ if (!strace_timestamps) return; /* this is a special magic topic for use with * git clone http://www.gnome.org/~federico/git/performance-scripts.git * http://www.gnome.org/~federico/news-2006-03.html#timeline-tools */ prefix = "MARK"; break; case GJS_DEBUG_GI_USAGE: prefix = "JS GI USE"; break; case GJS_DEBUG_MEMORY: prefix = "JS MEMORY"; break; case GJS_DEBUG_CONTEXT: prefix = "JS CTX"; break; case GJS_DEBUG_IMPORTER: prefix = "JS IMPORT"; break; case GJS_DEBUG_NATIVE: prefix = "JS NATIVE"; break; case GJS_DEBUG_KEEP_ALIVE: prefix = "JS KP ALV"; break; case GJS_DEBUG_GREPO: prefix = "JS G REPO"; break; case GJS_DEBUG_GNAMESPACE: prefix = "JS G NS"; break; case GJS_DEBUG_GOBJECT: prefix = "JS G OBJ"; break; case GJS_DEBUG_GFUNCTION: prefix = "JS G FUNC"; break; case GJS_DEBUG_GCLOSURE: prefix = "JS G CLSR"; break; case GJS_DEBUG_GBOXED: prefix = "JS G BXD"; break; case GJS_DEBUG_GENUM: prefix = "JS G ENUM"; break; case GJS_DEBUG_GPARAM: prefix = "JS G PRM"; break; case GJS_DEBUG_DATABASE: prefix = "JS DB"; break; case GJS_DEBUG_RESULTSET: prefix = "JS RS"; break; case GJS_DEBUG_WEAK_HASH: prefix = "JS WEAK"; break; case GJS_DEBUG_MAINLOOP: prefix = "JS MAINLOOP"; break; case GJS_DEBUG_PROPS: prefix = "JS PROPS"; break; case GJS_DEBUG_SCOPE: prefix = "JS SCOPE"; break; case GJS_DEBUG_HTTP: prefix = "JS HTTP"; break; case GJS_DEBUG_BYTE_ARRAY: prefix = "JS BYTE ARRAY"; break; case GJS_DEBUG_GERROR: prefix = "JS G ERR"; break; default: prefix = "???"; break; } if (!is_allowed_prefix(prefix)) return; va_start (args, format); s = g_strdup_vprintf (format, args); va_end (args); if (topic == GJS_DEBUG_STRACE_TIMESTAMP) { /* Put a magic string in strace output */ char *s2; s2 = g_strdup_printf("%s: gjs: %s", prefix, s); access(s2, F_OK); g_free(s2); } else { if (print_timestamp) { static gdouble previous = 0.0; gdouble total = g_timer_elapsed(timer, NULL) * 1000.0; gdouble since = total - previous; const char *ts_suffix; char *s2; if (since > 50.0) { ts_suffix = "!! "; } else if (since > 100.0) { ts_suffix = "!!! "; } else if (since > 200.0) { ts_suffix = "!!!!"; } else { ts_suffix = " "; } s2 = g_strdup_printf("%g %s%s", total, ts_suffix, s); g_free(s); s = s2; previous = total; } write_to_stream(logfp, prefix, s); } g_free(s); }