aboutsummaryrefslogtreecommitdiffstats
path: root/pseudo_util.c
diff options
context:
space:
mode:
authorPeter Seebach <peter.seebach@windriver.com>2016-02-23 17:28:55 -0600
committerPeter Seebach <peter.seebach@windriver.com>2016-02-23 17:29:45 -0600
commit2a7591e2931c893e6d1a635d2df5dd6120bf9952 (patch)
tree2b7d1f1d233544784f9e88d5624f195f365d9432 /pseudo_util.c
parent6b14fe133eea0148ad232e41bc12cc2e6e9c969f (diff)
downloadpseudo-2a7591e2931c893e6d1a635d2df5dd6120bf9952.tar.gz
pseudo-2a7591e2931c893e6d1a635d2df5dd6120bf9952.tar.bz2
pseudo-2a7591e2931c893e6d1a635d2df5dd6120bf9952.zip
Add event logger
For debugging the client/server startup, add an event logger to allow better recording of events that we may, or may not, want to dump out listings of later.
Diffstat (limited to 'pseudo_util.c')
-rw-r--r--pseudo_util.c196
1 files changed, 176 insertions, 20 deletions
diff --git a/pseudo_util.c b/pseudo_util.c
index 9d24362..6f8f6e8 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -29,6 +29,7 @@
#include <sys/stat.h>
#include <regex.h>
#include <time.h>
+#include <sys/time.h>
#include <unistd.h>
#include <limits.h>
@@ -69,9 +70,26 @@ static struct pseudo_variables pseudo_env[] = {
#ifdef PSEUDO_PROFILING
{ "PSEUDO_PROFILE_PATH", 19, NULL },
#endif
+ { "PSEUDO_EVLOG", 12, NULL },
+ { "PSEUDO_EVLOG_FILE", 17, NULL },
{ NULL, 0, NULL } /* Magic terminator */
};
+typedef struct {
+ struct timeval stamp;
+ int len;
+ char *data;
+} pseudo_evlog_entry;
+
+#define PSEUDO_EVLOG_ENTRIES 50
+#define PSEUDO_EVLOG_LENGTH 256
+static pseudo_evlog_entry event_log[PSEUDO_EVLOG_ENTRIES];
+static char *pseudo_evlog_buffer;
+static int pseudo_evlog_next_entry = 0;
+static void pseudo_evlog_set(char *);
+static void pseudo_evlog_flags_finalize(void);
+static unsigned long pseudo_debug_flags_in(char *);
+
/* -1 - init hasn't been run yet
* 0 - init has been run
* 1 - init is running
@@ -115,7 +133,7 @@ pseudo_has_unload(char * const *envp) {
if (pseudo_util_initted == -1)
pseudo_init_util();
while (pseudo_env[i].key && strcmp(pseudo_env[i].key, unload))
- ++i;
+ ++i;
if (pseudo_env[i].key && pseudo_env[i].value)
return 1;
@@ -205,9 +223,9 @@ pseudo_init_util(void) {
/* Somewhere we have to set the debug level.. */
env = pseudo_get_value("PSEUDO_DEBUG");
- if (env) {
+ if (env) {
int i;
- int level = atoi(env);
+ int level = atoi(env);
if (level > 0) {
for (i = 0; i < level; ++i) {
pseudo_debug_verbose();
@@ -216,12 +234,20 @@ pseudo_init_util(void) {
pseudo_debug_set(env);
}
pseudo_debug_flags_finalize();
- }
- free(env);
+ }
+ free(env);
+ env = pseudo_get_value("PSEUDO_EVLOG");
+ if (env) {
+ pseudo_evlog_set(env);
+ pseudo_evlog_flags_finalize();
+ }
+ free(env);
}
unsigned long pseudo_util_debug_flags = 0;
+unsigned long pseudo_util_evlog_flags = 0;
int pseudo_util_debug_fd = 2;
+int pseudo_util_evlog_fd = 2;
static int debugged_newline = 1;
static char pid_text[32];
static size_t pid_len;
@@ -389,30 +415,52 @@ pseudo_debug_verbose(void) {
}
}
+void
+pseudo_debug_set(char *s) {
+ pseudo_util_debug_flags = pseudo_debug_flags_in(s);
+}
+
+static void
+pseudo_evlog_set(char *s) {
+ pseudo_util_evlog_flags = pseudo_debug_flags_in(s);
+}
+
/* This exists because we don't want to allocate a bunch of strings
* and free them immediately if you have several flags set.
*/
-void
-pseudo_debug_flags_finalize(void) {
+static void
+pseudo_flags_finalize(unsigned long flags, char *value) {
char buf[PDBG_MAX + 1] = "", *s = buf;
for (int i = 0; i < PDBG_MAX; ++i) {
- if (pseudo_util_debug_flags & (1 << i)) {
+ if (flags & (1 << i)) {
*s++ = pseudo_debug_type_symbolic(i);
}
}
- pseudo_set_value("PSEUDO_DEBUG", buf);
+ pseudo_set_value(value, buf);
}
void
-pseudo_debug_set(char *s) {
+pseudo_debug_flags_finalize(void) {
+ pseudo_flags_finalize(pseudo_util_debug_flags, "PSEUDO_DEBUG");
+}
+
+void
+pseudo_evlog_flags_finalize(void) {
+ pseudo_flags_finalize(pseudo_util_evlog_flags, "PSEUDO_EVLOG");
+}
+
+static unsigned long
+pseudo_debug_flags_in(char *s) {
+ unsigned long flags = 0;
if (!s)
- return;
+ return flags;
for (; *s; ++s) {
int id = pseudo_debug_type_symbolic_id(*s);
if (id > 0) {
- pseudo_util_debug_flags |= (1 << id);
+ flags |= (1 << id);
}
}
+ return flags;
}
void
@@ -454,6 +502,89 @@ pseudo_diag(char *fmt, ...) {
return wrote;
}
+void
+pseudo_evlog_dump(void) {
+ char scratch[256], firstdate[64], lastdate[64];
+ time_t first = 0, last = 0;
+ int len;
+ int entries = 0;
+ struct tm first_tm, last_tm;
+ int wrote; /* ignoring write errors because there's nothing we can do */
+
+ for (int i = 0; i < PSEUDO_EVLOG_ENTRIES; ++i) {
+ pseudo_evlog_entry *e = &event_log[i];
+ if (!e->data || e->len < 0 || e->stamp.tv_sec == 0)
+ continue;
+ ++entries;
+ if (!first || e->stamp.tv_sec < first)
+ first = e->stamp.tv_sec;
+ if (!last || e->stamp.tv_sec > last)
+ last = e->stamp.tv_sec;
+ }
+ localtime_r(&first, &first_tm);
+ localtime_r(&last, &last_tm);
+ strftime(firstdate, 64, "%Y-%M-%D %H:%M:%S", &first_tm);
+ strftime(lastdate, 64, "%Y-%M-%D %H:%M:%S", &last_tm);
+
+ len = snprintf(scratch, 256, "event log for pid %d [%d entries]\n",
+ getpid(), entries);
+ if (len > 256)
+ len = 256;
+ wrote = write(pseudo_util_evlog_fd, scratch, len);
+ len = snprintf(scratch, 256, " first entry %s\n", firstdate);
+ wrote = write(pseudo_util_evlog_fd, scratch, len);
+ len = snprintf(scratch, 256, " last entry %s\n", lastdate);
+ wrote = write(pseudo_util_evlog_fd, scratch, len);
+
+ for (int i = 0; i < PSEUDO_EVLOG_ENTRIES; ++i) {
+ int entry = (pseudo_evlog_next_entry + i) % PSEUDO_EVLOG_ENTRIES;
+ pseudo_evlog_entry *ev = &event_log[entry];
+ if (!ev->data || ev->len <= 0)
+ continue;
+ localtime_r(&ev->stamp.tv_sec, &first_tm);
+ len = strftime(firstdate, 64, "%M:%S", &first_tm);
+ if (len) {
+ len = snprintf(scratch, 256, "%s.%03d: ", firstdate,
+ (int) (ev->stamp.tv_usec / 1000));
+ wrote = write(pseudo_util_evlog_fd, scratch, len);
+ } else {
+ wrote = write(pseudo_util_evlog_fd, "no timestamp: ", 14);
+ }
+ wrote = write(pseudo_util_evlog_fd, ev->data, ev->len);
+ }
+ (void) wrote;
+}
+
+int
+pseudo_evlog_internal(char *fmt, ...) {
+ va_list ap;
+ pseudo_evlog_entry *ev = &event_log[pseudo_evlog_next_entry++];
+
+ pseudo_evlog_next_entry %= PSEUDO_EVLOG_ENTRIES;
+
+ if (!ev->data) {
+ pseudo_evlog_buffer = malloc(PSEUDO_EVLOG_ENTRIES * PSEUDO_EVLOG_LENGTH);
+ if (pseudo_evlog_buffer) {
+ for (int i = 0; i < PSEUDO_EVLOG_ENTRIES; ++i) {
+ event_log[i].data = pseudo_evlog_buffer + (PSEUDO_EVLOG_LENGTH * i);
+ }
+ } else {
+ pseudo_diag("fatal: can't allocate event log storage.\n");
+ }
+ }
+
+ va_start(ap, fmt);
+ ev->len = vsnprintf(ev->data, PSEUDO_EVLOG_LENGTH, fmt, ap);
+ va_end(ap);
+ if (ev->len > PSEUDO_EVLOG_LENGTH) {
+ strcpy(ev->data + PSEUDO_EVLOG_LENGTH - 5, "...\n");
+ ev->len = PSEUDO_EVLOG_LENGTH - 1;
+ }
+ gettimeofday(&ev->stamp, NULL);
+
+ return ev->len;
+}
+
/* store pid in text form for prepending to messages */
void
pseudo_new_pid() {
@@ -749,14 +880,14 @@ pseudo_setupenv() {
free(pseudo_get_libdir());
free(pseudo_get_localstatedir());
- while (pseudo_env[i].key) {
+ while (pseudo_env[i].key) {
if (pseudo_env[i].value) {
setenv(pseudo_env[i].key, pseudo_env[i].value, 0);
pseudo_debug(PDBGF_ENV | PDBGF_VERBOSE, "pseudo_env: %s => %s\n",
pseudo_env[i].key, pseudo_env[i].value);
}
- i++;
- }
+ i++;
+ }
const char *ld_library_path = getenv(PRELINK_PATH);
char *libdir_path = pseudo_libdir_path(NULL);
@@ -846,9 +977,9 @@ pseudo_setupenvp(char * const *envp) {
++env_count;
}
- for (i = 0; pseudo_env[i].key; i++) {
+ for (i = 0; pseudo_env[i].key; i++) {
size_pseudoenv++;
- }
+ }
env_count += size_pseudoenv; /* We're going to over allocate */
@@ -1312,10 +1443,9 @@ pseudo_etc_file(const char *file, char *realname, int flags, const char **search
}
/* set up a log file */
-int
-pseudo_logfile(char *defname, int prefer_fd) {
+static int
+pseudo_logfile(char *filename, char *defname, int prefer_fd) {
char *pseudo_path;
- char *filename = pseudo_get_value("PSEUDO_DEBUG_FILE");
char *s;
#if PSEUDO_PORT_LINUX
extern char *program_invocation_short_name; /* glibcism */
@@ -1424,6 +1554,32 @@ pseudo_logfile(char *defname, int prefer_fd) {
return 0;
}
+int
+pseudo_debug_logfile(char *defname, int prefer_fd) {
+ char *filename = pseudo_get_value("PSEUDO_DEBUG_FILE");
+ int fd;
+
+ fd = pseudo_logfile(filename, defname, prefer_fd);
+ if (fd > -1) {
+ pseudo_util_debug_fd = fd;
+ return 0;
+ }
+ return 1;
+}
+
+int
+pseudo_evlog_logfile(char *defname, int prefer_fd) {
+ char *filename = pseudo_get_value("PSEUDO_EVLOG_FILE");
+ int fd;
+
+ fd = pseudo_logfile(filename, defname, prefer_fd);
+ if (fd > -1) {
+ pseudo_util_evlog_fd = fd;
+ return 0;
+ }
+ return 1;
+}
+
void
pseudo_stat32_from64(struct stat *buf32, const struct stat64 *buf) {
buf32->st_dev = buf->st_dev;