[PATCH phosphor-event] Event Logs to survive a reboot

Daniel Axtens dja at axtens.net
Thu Feb 4 00:21:10 AEDT 2016


Hi Chris,

>
> CA: A log rotate concept seems reasonable.  I can open an issue to ensure that happens.  Any traditional readings on the subject?

Traditionally in linux-land you'd stick a single log file in /var/log,
and use a program called logrotate to rotate it. Logrotate takes a
configuration snippet in /etc somewhere and then automatically can deal
with moving files, keeping a certain number, archiving old logs, sending
signals to processes so they know they've been rotated and can re-open
the log file, etc, etc. `man logrotate` is a good start: it'll be
running on any desktop or server linux system.

>
> CA: The Binary thought process is as follows (and I'm not married to the idea)
>   1) The debug developer data is presented as an array of bytes.  So I stored it as an array of bytes.  
>   2) Why an array of bytes and not a string?  Well debug data can be up to 2K.  Converting it to ascii makes each log stored as 4K.  
>   3) REST is the customer visible interface. no need for anyone outside of the service/support team to be relying on any internals
>
>
Hmm. These are decent points. My concern is that we then:
 - need to maintain the tool to decode them
 - suffer from increased debug turnaround.

I'm not clear on the disk-space limits in BMC land - 2k to 4k seems small to
me but maybe it's a real issue in the BMC case.

I'm not married to text logs either, but I think we should generally
prefer them to binary logs where there's not a compelling reason
otherwise.

Thanks for your helpful and thoughtful responses!

Regards,
Daniel

>
>> 3) Each log now has a timestamp of when the log reached the service
>> 4) I added a caching mechanism to reduce the io traffic if the the method is simply being called to capture the next parameter
>> 5) You will notice a mixture of c/c++.  This is because I want the test infrastructure to take advantage of c++ features
>>
>> Useful REST calls
>> ~~~~~~~~~~~~~~~~~
>> Note, dont forget to login first
>>
>> List all events
>> curl -k https://bmc/org/openbmc/records/events/
>>
>> Create an event log for testing purposes
>> curl -c cjar -b cjar -k -H "Content-Type: application/json" -X POST -d "{\"data\": []}" https://bmc/org/openbmc/records/events/action/acceptTestMessage
>>
>> Delete an event
>> curl -c cjar -b cjar -k -H "Content-Type: application/json" -X POST -d "{\"data\": []}" https://bmc/org/openbmc/records/events/1/action/delete
>>
>> Delete all events
>> curl -c cjar -b cjar -k -H "Content-Type: application/json" -X POST -d "{\"data\": []}" https://bmc/org/openbmc/records/events/action/clear
>> ---
>>  Makefile               |  29 ++--
>>  event_messaged.C       |  44 +++++
>>  event_messaged.c       | 341 ---------------------------------------
>>  event_messaged_sdbus.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  event_messaged_sdbus.h |  14 ++
>>  message.C              | 224 ++++++++++++++++++++++++++
>>  message.H              |  60 +++++++
>>  test.C                 |  92 +++++++++++
>>  8 files changed, 878 insertions(+), 351 deletions(-)
>>  create mode 100644 event_messaged.C
>>  delete mode 100644 event_messaged.c
>>  create mode 100644 event_messaged_sdbus.c
>>  create mode 100644 event_messaged_sdbus.h
>>  create mode 100644 message.C
>>  create mode 100644 message.H
>>  create mode 100644 test.C
>>
>> diff --git a/Makefile b/Makefile
>> index 4c2ba9b..903ac06 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -1,27 +1,36 @@
>> -TEST      = listfunc
>> -OBJS_TEST = $(TEST).o
>>  
>> -EXE     = event_messaged
>> +TEST      = test
>>  
>> -OBJS    = $(EXE).o   \
>> -          list.o 	 \
>> +EXE       = event_messaged
>> +EXE_OBJS  = $(EXE).o message.o event_messaged_sdbus.o list.o
>>  
>> +OBJS_TEST = $(TEST).o message.o
>> +
>> +CPPFLAGS  += -g -fpic -Wall -std=c++11
>>  
>>  DEPPKGS = libsystemd
>> -CC      ?= $(CROSS_COMPILE)gcc
>>  INCLUDES += $(shell pkg-config --cflags $(DEPPKGS)) 
>>  LIBS += $(shell pkg-config --libs $(DEPPKGS))
>>  
>> +
>> +
>>  all: $(EXE)
>>  
>>  %.o : %.c 
>>  	$(CC) -c $< $(CFLAGS) $(INCLUDES) -o $@
>>  
>> -$(EXE): $(OBJS)
>> -	$(CC) $^ $(LDFLAGS) $(LIBS) -o $@
>> +%.o : %.C
>> +	$(CXX) -c $< $(CPPFLAGS) -o $@
>> +
>> +
>> +$(EXE): $(EXE_OBJS)
>> +	$(CXX) $^ $(LDFLAGS) $(LIBS) -o $@
>> +
>>  
>>  $(TEST): $(OBJS_TEST)
>> -	$(CC) $^ $(LDFLAGS) $(LIBS) -o $@
>> +	$(CXX) $^ $(LDFLAGS) -o $@
>>  
>>  clean:
>> -	rm -f $(OBJS) $(EXE) *.o *.d
>> +	rm -f $(TEST) *.o *.so $(EXE)
>> +
>> +
>> diff --git a/event_messaged.C b/event_messaged.C
>> new file mode 100644
>> index 0000000..4376431
>> --- /dev/null
>> +++ b/event_messaged.C
>> @@ -0,0 +1,44 @@
>> +#include <iostream>
>> +#include "message.H"
>> +#include "event_messaged_sdbus.h"
>> +
>> +const char *glogname = "/var/lib/obmc/events";
>> +
>> +using namespace std;
>> +
>> +
>> +// Walk through all the saved logs and reload them in to dbus objects
>> +// Needed because on a reboot the existing logs need to be reloaded
>> +int load_existing_events(void) {
>> +
>> +    event_log_list log_list;
>> +    uint16_t       logid=0;
>> +
>> +    while (message_get_next_log(&logid, &log_list)) {
>> +        send_log_to_dbus(logid);
>> +    }
>> +    
>> +    return 0;
>> +}
>> +
>> +int main(int argc, char *argv[]) {
>> +
>> +    int rc = 0;
>> +
>> +    if ((rc = build_bus()) < 0) {
>> +        fprintf(stderr, "Event Messager failed to connect to dbus rc=%d", rc);
>> +        goto finish;
>> +    }
>> +
>> +    if ((rc = load_existing_events()) < 0) {
>> +        fprintf(stderr, "Event Messager failed add previous logs to dbus rc=%d", rc);
>> +        goto finish;
>> +    }
>> +
>> +    rc = start_event_monitor();
>> +
>> +    finish:
>> +    cleanup_event_monitor();
>> +
>> +    return rc;
>> +}
>> \ No newline at end of file
>> diff --git a/event_messaged.c b/event_messaged.c
>> deleted file mode 100644
>> index 0c75e3a..0000000
>> --- a/event_messaged.c
>> +++ /dev/null
>> @@ -1,341 +0,0 @@
>> -#include <stdio.h>
>> -#include <stdlib.h>
>> -#include <errno.h>
>> -#include <stddef.h>
>> -#include <systemd/sd-bus.h>
>> -#include "list.h"
>> -
>> -uint16_t g_logid = 0;
>> -sd_bus *bus = NULL;
>> -List *glist;
>> -
>> -
>> -int create_new_log_event(void *userdata,
>> -                         const char *message,
>> -                         const char *severity,
>> -                         const char *association,
>> -                         const char *reportedby,
>> -                         uint8_t *p,
>> -                         size_t n);
>> -
>> -typedef struct messageEntry_t {
>> -	char    *message;
>> -	char    *severity;
>> -	char    *reportedby;
>> -	char    *association;
>> -	uint8_t *debugbytes;
>> -	size_t   debuglength;
>> -	size_t   logid;
>> -
>> -	sd_bus_slot *messageslot;
>> -	sd_bus_slot *deleteslot;
>> -
>> -} messageEntry_t;
>> -
>> -
>> -void message_storage_delete(messageEntry_t *m) {
>> -
>> -	char *path;
>> -	int r;
>> -
>> -	asprintf(&path, "/org/openbmc/records/events/%d", m->logid);
>> -
>> -
>> -	printf("Attempting to delete %s\n", path);
>> -
>> -	free(m->message);
>> -	free(m->severity);
>> -	free(m->reportedby);
>> -	free(m->association);
>> -	free(m->debugbytes);
>> -
>> -
>> -	r = sd_bus_emit_object_removed(bus, path);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to emit the delete signal %s\n", strerror(-r));
>> -		return;
>> -	}
>> -
>> -	sd_bus_slot_unref(m->messageslot);
>> -	sd_bus_slot_unref(m->deleteslot);
>> -
>> -	free(m);
>> -
>> -	return;
>> -}
>> -
>> -
>> -
>> -void message_add(messageEntry_t **n, 
>> -                const char *message,
>> -                const char *severity,
>> -                const char *association,
>> -                const char *reportedby,
>> -                size_t      logid,
>> -                uint8_t    *data,
>> -                size_t      datalen)
>> -{
>> -
>> -	messageEntry_t *p = *n = malloc(sizeof(messageEntry_t));
>> -
>> -	asprintf(&(*n)->message,     "%s", message);
>> -	asprintf(&(*n)->severity,    "%s", severity);
>> -	asprintf(&(*n)->association, "%s", association);
>> -	asprintf(&(*n)->reportedby,  "%s", reportedby);
>> -
>> -	(*n)->logid       = logid;
>> -	(*n)->debugbytes  = (uint8_t*) malloc (datalen);
>> -	(*n)->debuglength = datalen;
>> -	memcpy((*n)->debugbytes, data, datalen);
>> -
>> -	(*n)->messageslot = NULL;
>> -	(*n)->deleteslot  = NULL;
>> -	return;
>> -}
>> -
>> -
>> -static int get_message_dd(sd_bus *bus,
>> -                          const char *path,
>> -                          const char *interface,
>> -                          const char *property,
>> -                          sd_bus_message *reply,
>> -                          void *userdata,
>> -                          sd_bus_error *error) {
>> -
>> -	int r;
>> -	messageEntry_t *p = (messageEntry_t *)userdata;
>> -	
>> -	r = sd_bus_message_append_array(reply, 'y', p->debugbytes, p->debuglength);
>> -	if (r < 0) {
>> -	  printf("Error building array for property %s\n", strerror(-r));
>> -	}
>> -
>> -	return r;
>> -}
>> -
>> -
>> -/////////////////////////////////////////////////////////////
>> -// Receives an array of bytes as an esel error log
>> -// returns the messageid in 2 byte format
>> -//  
>> -//  S1 - Message - Simple sentence about the fail
>> -//  S2 - Severity - How bad of a problem is this
>> -//  S3 - Association - sensor path
>> -//  ay - Detailed data - developer debug information
>> -//
>> -/////////////////////////////////////////////////////////////
>> -static int method_accept_host_message(sd_bus_message *m, 
>> -                                      void *userdata, 
>> -                                      sd_bus_error *ret_error) {
>> -
>> -	char *message, *severity, *association;
>> -	size_t   n = 4;
>> -	uint8_t *p;
>> -	int r;
>> -
>> -	r = sd_bus_message_read(m, "sss", &message, &severity, &association);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to parse the String parameter: %s\n", strerror(-r));
>> -		return r;
>> -	}
>> -
>> -	r = sd_bus_message_read_array(m, 'y', (const void **)&p, &n);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to parse the array of bytes parameter: %s\n", strerror(-r));
>> -		return r;
>> -	}
>> -
>> -	create_new_log_event(userdata, message, severity, association, "Host", p, n);
>> -
>> -	return sd_bus_reply_method_return(m, "q", g_logid);
>> -}
>> -
>> -
>> -static int method_accept_test_message(sd_bus_message *m, 
>> -                                      void *userdata, 
>> -                                      sd_bus_error *ret_error) {
>> -
>> -	uint8_t p[] = {0x30, 0x32, 0x34, 0x36};
>> -
>> -	create_new_log_event(userdata, "Testing Message", "Info", "Association", "Test", p, 4);
>> -
>> -	return sd_bus_reply_method_return(m, "q", g_logid);
>> -}
>> -
>> -
>> -static int method_clearall(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
>> -
>> -	Node *n;
>> -
>> -	// This deletes one log at a time and seeing how the
>> -	// list shrinks using the NULL works fine here
>> -	while (n = list_get_next_node(glist, NULL)) {
>> -		message_storage_delete(n->data);
>> -		list_delete_node(glist, n);
>> -	}
>> -
>> -	return sd_bus_reply_method_return(m, "q", 0);
>> -}
>> -
>> -
>> -static int method_deletelog(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
>> -
>> -	Node *n = (Node*)userdata;
>> -
>> -	message_storage_delete(n->data);
>> -	list_delete_node(glist, n);
>> -
>> -	return sd_bus_reply_method_return(m, "q", 0);
>> -}
>> -
>> -
>> -
>> -static const sd_bus_vtable recordlog_vtable[] = {
>> -	SD_BUS_VTABLE_START(0),
>> -	SD_BUS_METHOD("acceptHostMessage", "sssay", "q", method_accept_host_message, SD_BUS_VTABLE_UNPRIVILEGED),
>> -	SD_BUS_METHOD("acceptTestMessage", NULL, "q", method_accept_test_message, SD_BUS_VTABLE_UNPRIVILEGED),
>> -	SD_BUS_METHOD("Clear", NULL, "q", method_clearall, SD_BUS_VTABLE_UNPRIVILEGED),
>> -	SD_BUS_VTABLE_END
>> -};
>> -
>> -static const sd_bus_vtable log_vtable[] = {
>> -	SD_BUS_VTABLE_START(0),
>> -	SD_BUS_PROPERTY("Association", "s", NULL, offsetof(messageEntry_t, association), SD_BUS_VTABLE_PROPERTY_CONST),
>> -	SD_BUS_PROPERTY("Message",  "s", NULL, offsetof(messageEntry_t, message), SD_BUS_VTABLE_PROPERTY_CONST),
>> -	SD_BUS_PROPERTY("Severity", "s", NULL, offsetof(messageEntry_t, severity), SD_BUS_VTABLE_PROPERTY_CONST),
>> -	SD_BUS_PROPERTY("Reported_By", "s", NULL, offsetof(messageEntry_t, reportedby),  SD_BUS_VTABLE_PROPERTY_CONST),
>> -	SD_BUS_PROPERTY("DevelopmentData", "ay", get_message_dd,0, SD_BUS_VTABLE_PROPERTY_CONST),
>> -	SD_BUS_VTABLE_END
>> -};
>> -
>> -
>> -static const sd_bus_vtable recordlog_delete_vtable[] = {
>> -	SD_BUS_VTABLE_START(0),
>> -	SD_BUS_METHOD("Delete", NULL, "q", method_deletelog, SD_BUS_VTABLE_UNPRIVILEGED),
>> -	SD_BUS_VTABLE_END
>> -};
>> -
>> -uint16_t get_new_log_number() {
>> -	return ++g_logid;
>> -}
>> -
>> -int create_new_log_event(void *userdata,
>> -                         const char *message,
>> -                         const char *severity,
>> -                         const char *association,
>> -                         const char *reportedby,
>> -                         uint8_t *p, 
>> -                         size_t n) {
>> -	char loglocation[64];
>> -	int r;
>> -	messageEntry_t *m;
>> -	Node *node;
>> -	uint16_t logid = get_new_log_number();
>> -
>> -
>> -	snprintf(loglocation, sizeof(loglocation), "/org/openbmc/records/events/%d", logid);
>> -
>> -	message_add(&m, message, severity, association, reportedby, logid, p, n);
>> -
>> -	node = list_add_node(glist, m);
>> -
>> -	r = sd_bus_add_object_vtable(bus,
>> -	                             &m->messageslot,
>> -	                             loglocation,
>> -	                             "org.openbmc.record",
>> -	                             log_vtable,
>> -	                             m);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to acquire service name: %s %s\n", loglocation, strerror(-r));
>> -		message_storage_delete(m);
>> -		list_delete_last_node(glist);
>> -		return 0;
>> -	}
>> -
>> -	r = sd_bus_add_object_vtable(bus,
>> -	                             &m->deleteslot,
>> -	                             loglocation,
>> -	                             "org.openbmc.Object.Delete",
>> -	                             recordlog_delete_vtable,
>> -	                             node);
>> -
>> -	printf("Event Log added %s\n", loglocation);
>> -
>> -	r = sd_bus_emit_object_added(bus, loglocation);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to emit signal %s\n", strerror(-r));
>> -		return 0;
>> -	}
>> -
>> -
>> -
>> -	return logid;
>> -}
>> -
>> -
>> -int start_event_recording(void) {
>> -
>> -	int r;
>> -
>> -	sd_bus_slot *slot;
>> -
>> -	/* Connect to the user bus this time */
>> -	r = sd_bus_open_system(&bus);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
>> -		goto finish;
>> -	}
>> -
>> -	/* Install the object */
>> -	r = sd_bus_add_object_vtable(bus,
>> -	                             &slot,
>> -	                             "/org/openbmc/records/events",  /* object path */
>> -	                             "org.openbmc.recordlog",   /* interface name */
>> -	                             recordlog_vtable,
>> -	                             NULL);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
>> -		goto finish;
>> -	}
>> -	
>> -	/* Take a well-known service name so that clients can find us */
>> -	r = sd_bus_request_name(bus, "org.openbmc.records.events", 0);
>> -	if (r < 0) {
>> -		fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
>> -		goto finish;
>> -	}
>> -
>> -	r = sd_bus_add_object_manager(bus, NULL, "/org/openbmc/records/events") ;
>> -	if (r < 0) {
>> -		fprintf(stderr, "Object Manager failure  %s\n", strerror(-r));
>> -		return 0;
>> -	}
>> -
>> -	for (;;) {
>> -		r = sd_bus_process(bus, NULL);
>> -		if (r < 0) {
>> -			fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
>> -			goto finish;
>> -		}
>> -		if (r > 0)
>> -			continue;
>> -
>> -		r = sd_bus_wait(bus, (uint64_t) -1);
>> -		if (r < 0) {
>> -			fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
>> -			goto finish;
>> -		}
>> -	}
>> -	finish:
>> -		sd_bus_slot_unref(slot);
>> -		sd_bus_unref(bus);
>> -
>> -	return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
>> -}
>> -
>> -
>> -int main(int argc, char *argv[]) {
>> -
>> -	glist = list_create();
>> -	return start_event_recording();
>> -}
>> \ No newline at end of file
>> diff --git a/event_messaged_sdbus.c b/event_messaged_sdbus.c
>> new file mode 100644
>> index 0000000..fa83e5c
>> --- /dev/null
>> +++ b/event_messaged_sdbus.c
>> @@ -0,0 +1,425 @@
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <errno.h>
>> +#include <stddef.h>
>> +#include <systemd/sd-bus.h>
>> +#include "message.H"
>> +#include "list.h"
>> +#include "event_messaged_sdbus.h"
>> +
>> +/*****************************************************************************/
>> +/* This set of functions are responsible for interactions with events over   */
>> +/* dbus.  Logs come in a couple of different ways...                         */ 
>> +/*     1) From the calls from acceptHostMessage, acceptTestMessage           */
>> +/*     2) At startup and logs that exist alreafy are re-added                */
>> +/*                                                                           */
>> +/* event_record_t when loaded contain all strings and data stream for a log  */
>> +/*                                                                           */
>> +/* Functions naming convention                                               */
>> +/*     prop_x    : callable dbus properties.                                 */
>> +/*     method_x  : callable dbus functions.                                  */
>> +/*                                                                           */
>> +/*****************************************************************************/
>> +
>> +
>> +
>> +sd_bus      *bus   = NULL;
>> +sd_bus_slot *slot  = NULL;
>> +List        *glist = NULL;
>> +
>> +event_record_t *gCachedRec = NULL;
>> +
>> +static int remove_log_from_dbus(Node *node);
>> +
>> +typedef struct messageEntry_t {
>> +
>> +	size_t       logid;
>> +	sd_bus_slot *messageslot;
>> +	sd_bus_slot *deleteslot;
>> +
>> +} messageEntry_t;
>> +
>> +
>> +static void message_entry_close(messageEntry_t *m) {
>> +	free(m);
>> +	return;
>> +}
>> +
>> +static void message_entry_new(messageEntry_t **m, uint16_t logid) {
>> +	*m          = malloc(sizeof(messageEntry_t));
>> +	(*m)->logid = logid;
>> +	return;
>> +}
>> +
>> +// After calling this function the gCachedRec will be set
>> +static event_record_t* message_record_open(uint16_t logid) {
>> +
>> +	int r = 0;
>> +	event_record_t *rec;
>> +
>> +	// A simple caching technique because each 
>> +	// property needs to extract data from the
>> +	// same data blob.  
>> +	if (gCachedRec == NULL) {
>> +		if (message_load_log(logid, &rec)) {
>> +			gCachedRec = rec;
>> +			return gCachedRec;
>> +		} else 
>> +			return NULL;
>> +	} 
>> +
>> +	if (logid == gCachedRec->logid) {
>> +		r = 1;
>> +
>> +	} else {
>> +		message_free_log(gCachedRec);
>> +		gCachedRec = NULL;
>> +
>> +		r = message_load_log(logid, &rec);
>> +		if (r)
>> +			gCachedRec = rec;
>> +	}
>> +
>> +	return (r ? gCachedRec : NULL);
>> +}
>> +
>> +
>> +
>> +static int prop_message(sd_bus *bus,
>> +                       const char *path,
>> +                       const char *interface,
>> +                       const char *property,
>> +                       sd_bus_message *reply,
>> +                       void *userdata,
>> +                       sd_bus_error *error) {
>> +
>> +	int r=0;
>> +	messageEntry_t *m = (messageEntry_t*) userdata;
>> +	char *p;
>> +	struct tm *tm_info;
>> +    char buffer[32];
>> +    event_record_t *rec;
>> +
>> +	rec = message_record_open(m->logid);
>> +
>> +	if (!rec) {
>> +		fprintf(stderr,"Warning missing evnet log for %d\n", m->logid);
>> +		sd_bus_error_set(error,  SD_BUS_ERROR_FILE_NOT_FOUND,"Could not find log file");
>> +        return -1;
>> +	}
>> +
>> +	if (!strncmp("Message", property, 7)) 
>> +		p = rec->message;
>> +	else if (!strncmp("Severity", property, 8))
>> +		p = rec->severity;
>> +	else if (!strncmp("Association", property, 11))
>> +		p = rec->association;
>> +	else if (!strncmp("Reported_By", property, 11))
>> +		p = rec->reportedby;
>> +	else if (!strncmp("Time", property, 4)) {
>> +		tm_info = localtime(&rec->timestamp);
>> +		strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", tm_info);
>> +		p    = buffer;
>> +	}
>> +	else
>> +		p = "";
>> +
>> +	r = sd_bus_message_append(reply, "s", p);
>> +	if (r < 0) {
>> +	    fprintf(stderr,"Error building array for property %s\n", strerror(-r));
>> +	}
>> +
>> +
>> +	return r;
>> +}
>> +
>> +
>> +static int prop_message_dd(sd_bus *bus,
>> +                       const char *path,
>> +                       const char *interface,
>> +                       const char *property,
>> +                       sd_bus_message *reply,
>> +                       void *userdata,
>> +                       sd_bus_error *error) {
>> +
>> +    event_record_t *rec;
>> +    messageEntry_t *m = (messageEntry_t*) userdata;
>> +
>> +	rec = message_record_open(m->logid);
>> +
>> +	if (!rec) {
>> +		sd_bus_error_set(error,  SD_BUS_ERROR_FILE_NOT_FOUND,"Could not find log file");
>> +        return -1;
>> +    }
>> +	return sd_bus_message_append_array(reply, 'y', rec->p, rec->n);
>> +}
>> +
>> +/////////////////////////////////////////////////////////////
>> +// Receives an array of bytes as an esel error log
>> +// returns the messageid in 2 byte format
>> +//  
>> +//  S1 - Message - Simple sentence about the fail
>> +//  S2 - Severity - How bad of a problem is this
>> +//  S3 - Association - sensor path
>> +//  ay - Detailed data - developer debug information
>> +//
>> +/////////////////////////////////////////////////////////////
>> +static int method_accept_host_message(sd_bus_message *m,
>> +                                      void *userdata,
>> +                                      sd_bus_error *ret_error) {
>> +
>> +	char *message, *severity, *association;
>> +	size_t   n = 4;
>> +	uint8_t *p;
>> +	int r;
>> +	uint16_t logid;
>> +	event_record_t rec;
>> +
>> +	r = sd_bus_message_read(m, "sss", &message, &severity, &association);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to parse the String parameter: %s\n", strerror(-r));
>> +		return r;
>> +	}
>> +
>> +	r = sd_bus_message_read_array(m, 'y', (const void **)&p, &n);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to parse the array of bytes parameter: %s\n", strerror(-r));
>> +		return r;
>> +	}
>> +
>> +    rec.message     = (char*) message;
>> +    rec.severity    = (char*) severity;
>> +    rec.association = (char*) association;
>> +    rec.reportedby  = (char*) "Host";
>> +    rec.p           = (uint8_t*) p;
>> +    rec.n           = n;
>> +
>> +
>> +	logid = message_create_new_log_event(&rec);
>> +
>> +	if (logid) 
>> +		r = send_log_to_dbus(logid);
>> +
>> +	return sd_bus_reply_method_return(m, "q", logid);
>> +}
>> +
>> +
>> +static int method_accept_test_message(sd_bus_message *m,
>> +                                      void *userdata, 
>> +                                      sd_bus_error *ret_error) {
>> +
>> +	uint8_t p[] = {0x30, 0x32, 0x34, 0x36};
>> +	uint16_t logid;
>> +	event_record_t rec;
>> +
>> +    rec.message     = (char*) "Testing Message";
>> +    rec.severity    = (char*) "Info";
>> +    rec.association = (char*) "Association";
>> +    rec.reportedby  = (char*) "Test";
>> +    rec.p           = (uint8_t*) p;
>> +    rec.n           = sizeof(*p);
>> +
>> +	logid = message_create_new_log_event(&rec);
>> +	send_log_to_dbus(logid);
>> +
>> +	return sd_bus_reply_method_return(m, "q", logid);
>> +}
>> +
>> +
>> +static int method_clearall(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
>> +	Node *n;
>> +	messageEntry_t *p;
>> +	
>> +	// This deletes one log at a time and seeing how the
>> +	// list shrinks using the NULL works fine here
>> +	while (n = list_get_next_node(glist, NULL)) {
>> +		p = (messageEntry_t *) n->data;
>> +		message_delete_log(p->logid);
>> +		remove_log_from_dbus(n);
>> +	}
>> +
>> +	return sd_bus_reply_method_return(m, "q", 0);
>> +}
>> +
>> +
>> +static int method_deletelog(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
>> +
>> +	Node *n = (Node*)userdata;
>> +	messageEntry_t *p = (messageEntry_t *) n->data;
>> +
>> +	message_delete_log(p->logid);
>> +	remove_log_from_dbus(n);
>> +	return sd_bus_reply_method_return(m, "q", 0);
>> +}
>> +
>> +
>> +
>> +static const sd_bus_vtable recordlog_vtable[] = {
>> +	SD_BUS_VTABLE_START(0),
>> +	SD_BUS_METHOD("acceptHostMessage", "sssay", "q", method_accept_host_message, SD_BUS_VTABLE_UNPRIVILEGED),
>> +	SD_BUS_METHOD("acceptTestMessage", NULL, "q", method_accept_test_message, SD_BUS_VTABLE_UNPRIVILEGED),
>> +	SD_BUS_METHOD("Clear", NULL, "q", method_clearall, SD_BUS_VTABLE_UNPRIVILEGED),
>> +	SD_BUS_VTABLE_END
>> +};
>> +
>> +static const sd_bus_vtable log_vtable[] = {
>> +	SD_BUS_VTABLE_START(0),   
>> +	SD_BUS_PROPERTY("Association",      "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
>> +	SD_BUS_PROPERTY("Message",          "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
>> +	SD_BUS_PROPERTY("Severity",         "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
>> +	SD_BUS_PROPERTY("Reported_By",      "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
>> +	SD_BUS_PROPERTY("Time",             "s", prop_message, 0, SD_BUS_VTABLE_PROPERTY_CONST),
>> +	SD_BUS_PROPERTY("DevelopmentData", "ay", prop_message_dd ,0, SD_BUS_VTABLE_PROPERTY_CONST),
>> +	SD_BUS_VTABLE_END
>> +};
>> +
>> +
>> +static const sd_bus_vtable recordlog_delete_vtable[] = {
>> +	SD_BUS_VTABLE_START(0),
>> +	SD_BUS_METHOD("delete", NULL, "q", method_deletelog, SD_BUS_VTABLE_UNPRIVILEGED),
>> +	SD_BUS_VTABLE_END
>> +};
>> +
>> +static int remove_log_from_dbus(Node *node) {
>> +	
>> +	messageEntry_t *p = (messageEntry_t *) node->data;
>> +	int r;
>> +	char buffer[32];
>> +
>> +	snprintf(buffer, sizeof(buffer), "/org/openbmc/records/events/%d", p->logid);
>> +
>> +	printf("Attempting to delete %s\n", buffer);
>> +
>> +	r = sd_bus_emit_object_removed(bus, buffer);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to emit the delete signal %s\n", strerror(-r));
>> +		return -1;
>> +	}	
>> +	sd_bus_slot_unref(p->messageslot);
>> +	sd_bus_slot_unref(p->deleteslot);
>> +
>> +	message_entry_close(p);
>> +	list_delete_node(glist, node);
>> +
>> +	return 0;
>> +}
>> +
>> +int send_log_to_dbus(const uint16_t logid) {
>> +
>> +	char loglocation[64];
>> +	int r;
>> +	messageEntry_t *m;
>> +	Node *node;
>> +
>> +
>> +	snprintf(loglocation, sizeof(loglocation), "/org/openbmc/records/events/%d", logid);
>> +
>> +	message_entry_new(&m, logid);
>> +
>> +	node = list_add_node(glist, m);
>> +
>> +	r = sd_bus_add_object_vtable(bus,
>> +	                             &m->messageslot,
>> +	                             loglocation,
>> +	                             "org.openbmc.record",
>> +	                             log_vtable,
>> +	                             m);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to acquire service name: %s %s\n", loglocation, strerror(-r));
>> +		message_entry_close(m);
>> +		list_delete_last_node(glist);
>> +		return 0;
>> +	}
>> +
>> +	r = sd_bus_add_object_vtable(bus,
>> +	                             &m->deleteslot,
>> +	                             loglocation,
>> +	                             "org.openbmc.Object.Delete",
>> +	                             recordlog_delete_vtable,
>> +	                             node);
>> +	
>> +	printf("Event Log added %s\n", loglocation);
>> +
>> +	r = sd_bus_emit_object_added(bus, loglocation);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to emit signal %s\n", strerror(-r));
>> +		return 0;
>> +	}
>> +
>> +	return logid;
>> +}
>> +
>> +
>> +int start_event_monitor(void) {
>> +
>> +	int r;
>> +
>> +	for (;;) {
>> +
>> +		r = sd_bus_process(bus, NULL);
>> +		if (r < 0) {
>> +			fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
>> +			break;
>> +		}
>> +
>> +		if (r > 0)
>> +			continue;
>> +
>> +		r = sd_bus_wait(bus, (uint64_t) -1);
>> +		if (r < 0) {
>> +			fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
>> +			break;
>> +		}
>> +	}
>> +
>> +	return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
>> +}
>> +
>> +
>> +/* Only thing we are doing in this function is to get a connection on the dbus */
>> +int build_bus(void) {
>> +
>> +	int r = 0;
>> +
>> +	glist = list_create();
>> +	/* Connect to the system bus */
>> +	r = sd_bus_open_system(&bus);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
>> +		goto finish;
>> +	}
>> +
>> +	/* Install the object */
>> +	r = sd_bus_add_object_vtable(bus,
>> +	                             &slot,
>> +	                             "/org/openbmc/records/events",  /* object path */
>> +	                             "org.openbmc.recordlog",   /* interface name */
>> +	                             recordlog_vtable,
>> +	                             NULL);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
>> +		goto finish;
>> +	}
>> +
>> +	/* Take a well-known service name so that clients can find us */
>> +	r = sd_bus_request_name(bus, "org.openbmc.records.events", 0);
>> +	if (r < 0) {
>> +		fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
>> +	}	
>> +	
>> +	/* You want to add an object manager to support deleting stuff  */
>> +	/* without it, dbus can show interfaces that no longer exist */
>> +	r = sd_bus_add_object_manager(bus, NULL, "/org/openbmc/records/events");
>> +	if (r < 0) {
>> +		fprintf(stderr, "Object Manager failure  %s\n", strerror(-r));
>> +	}
>> +
>> +
>> +	finish:
>> +	return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
>> +}
>> +
>> +void cleanup_event_monitor(void) {
>> +	sd_bus_slot_unref(slot);
>> +	sd_bus_unref(bus);
>> +}
>> \ No newline at end of file
>> diff --git a/event_messaged_sdbus.h b/event_messaged_sdbus.h
>> new file mode 100644
>> index 0000000..a6aac94
>> --- /dev/null
>> +++ b/event_messaged_sdbus.h
>> @@ -0,0 +1,14 @@
>> +#include <stddef.h>
>> +
>> +#ifdef __cplusplus
>> +extern "C"  {
>> +#endif
>> +	int start_event_monitor(void);
>> +	int build_bus(void);
>> +	int send_log_to_dbus(const uint16_t logid);
>> +	void cleanup_event_monitor(void);
>> +#ifdef __cplusplus
>> +}
>> +#endif
>> +
>> +
>> diff --git a/message.C b/message.C
>> new file mode 100644
>> index 0000000..31a545a
>> --- /dev/null
>> +++ b/message.C
>> @@ -0,0 +1,224 @@
>> +#include <iostream>
>> +#include <fstream>
>> +#include <iomanip>
>> +#include <cstdint>
>> +#include <string>
>> +#include <sys/types.h> 
>> +#include <dirent.h> 
>> +#include <sstream>
>> +#include <sys/stat.h>
>> +#include <cstring>
>> +#include "message.H"
>> +#include <time.h>
>> +#include <stddef.h>
>> +#include <cstdio>
>> +
>> +using namespace std;
>> +
>> +const uint32_t g_eyecatcher = 0x4F424D43; // OBMC
>> +const uint16_t g_version    = 1;
>> +
>> +struct logheader_t {
>> +    uint32_t eyecatcher;
>> +    uint16_t version;
>> +    uint16_t logid;
>> +    time_t   timestamp;
>> +    uint16_t detailsoffset;
>> +    uint16_t messagelen;
>> +    uint16_t severitylen;
>> +    uint16_t associationlen;
>> +    uint16_t reportedbylen;
>> +    uint16_t debugdatalen;
>> +};
>> +
>> +uint16_t g_logid = 0;
>> +
>> +extern const char *glogname;
>> +
>> +static uint16_t get_new_log_number(void) {
>> +    return ++g_logid;
>> +}
>> +
>> +static void update_latest_logid(uint16_t logid) {
>> +    if (logid > g_logid)
>> +        g_logid = logid;
>> +    return;
>> +}
>> +
>> +inline uint16_t GETLEN(const char *s) {
>> +    return (uint16_t) (1 + strlen(s));
>> +}
>> +
>> +static uint16_t create_log_event(event_record_t *rec) {
>> +
>> +    std::ostringstream buffer;
>> +    ofstream myfile;
>> +    logheader_t hdr;
>> +
>> +
>> +    buffer << glogname << "/" << int(rec->logid) ;
>> +
>> +    cout << buffer.str() << endl;
>> +
>> +    hdr.eyecatcher     = g_eyecatcher;
>> +    hdr.version        = g_version;
>> +    hdr.logid          = rec->logid;
>> +    hdr.timestamp      = time(NULL);
>> +    hdr.detailsoffset  = offsetof(logheader_t, messagelen);
>> +    hdr.messagelen     = GETLEN(rec->message);
>> +    hdr.severitylen    = GETLEN(rec->severity);
>> +    hdr.associationlen = GETLEN(rec->association);
>> +    hdr.reportedbylen  = GETLEN(rec->reportedby);
>> +    hdr.debugdatalen   = rec->n;
>> +
>> +    myfile.open(buffer.str() , ios::out|ios::binary);
>> +    myfile.write((char*) &hdr, sizeof(hdr));
>> +    myfile.write((char*) rec->message, hdr.messagelen);
>> +    myfile.write((char*) rec->severity, hdr.severitylen);
>> +    myfile.write((char*) rec->association, hdr.associationlen);
>> +    myfile.write((char*) rec->reportedby, hdr.reportedbylen);
>> +    myfile.write((char*) rec->p, hdr.debugdatalen);
>> +    myfile.close();
>> +
>> +    return rec->logid;
>> +}
>> +
>> +static int is_file_a_log(string str) {
>> +
>> +    std::ostringstream buffer;
>> +    ifstream f;
>> +    logheader_t hdr;
>> +
>> +    if (!str.compare("."))
>> +        return 0;
>> +    if (!str.compare(".."))
>> +        return 0;
>> +
>> +    buffer << glogname << "/" << str;
>> +
>> +    f.open( buffer.str(), ios::binary);
>> +
>> +    if (!f.good()) {
>> +        return 0;
>> +    }
>> +
>> +    f.read((char*)&hdr, sizeof(hdr));
>> +
>> +    if (hdr.eyecatcher != g_eyecatcher)
>> +        return 0;
>> +
>> +    return 1;
>> +}
>> +
>> +
>> +
>> +int message_load_log(uint16_t logid, event_record_t **rec) {
>> +
>> +    std::ostringstream buffer;
>> +    ifstream f;
>> +    logheader_t hdr;
>> +
>> +    buffer << glogname << "/" << int(logid);
>> +
>> +    f.open( buffer.str(), ios::binary);
>> +
>> +    if (!f.good()) {
>> +        return 0;
>> +    }
>> +
>> +    *rec = new event_record_t;
>> +
>> +    f.read((char*)&hdr, sizeof(hdr));
>> +
>> +    (*rec)->logid     = hdr.logid;
>> +    (*rec)->timestamp = hdr.timestamp;
>> +
>> +
>> +    (*rec)->message = new char[hdr.messagelen];
>> +    f.read((*rec)->message, hdr.messagelen);
>> +
>> +    (*rec)->severity = new char[hdr.severitylen];
>> +    f.read((*rec)->severity, hdr.severitylen);
>> +
>> +    (*rec)->association = new char[hdr.associationlen];
>> +    f.read((*rec)->association, hdr.associationlen);
>> +
>> +    (*rec)->reportedby = new char[hdr.reportedbylen];
>> +    f.read((*rec)->reportedby, hdr.reportedbylen);
>> +
>> +    (*rec)->p = new uint8_t[hdr.debugdatalen];
>> +    f.read((char*)(*rec)->p, hdr.debugdatalen);
>> +    (*rec)->n = hdr.debugdatalen;
>> +
>> +
>> +    f.close();
>> +    return logid;
>> +}
>> +
>> +void message_free_log(event_record_t *rec) {
>> +
>> +    delete[] rec->message;
>> +    delete[] rec->severity;
>> +    delete[] rec->association;
>> +    delete[] rec->reportedby;
>> +    delete[] rec->p;
>> +    delete rec;
>> +
>> +    return ;
>> +}
>> +
>> +int message_delete_log(uint16_t logid) {
>> +
>> +    std::stringstream buffer;
>> +    string s;
>> +
>> +    buffer << glogname << "/" << int(logid);
>> +
>> +    s = buffer.str();
>> +    std::remove(s.c_str());
>> +
>> +    return 0;
>> +}
>> +
>> +
>> +int message_get_next_log(uint16_t *logid, event_log_list *log_list) {
>> +
>> +    std::ostringstream buffer;
>> +    struct dirent *ent;
>> +
>> +    if (*logid==0)
>> +        log_list->dirp = opendir(glogname);
>> +
>> +    if(log_list->dirp)
>> +    {
>> +        do {
>> +            ent = readdir(log_list->dirp);
>> +
>> +            if (ent == NULL)
>> +                break;
>> +
>> +            string str(ent->d_name);
>> +
>> +            if (is_file_a_log(str)) {
>> +                *logid = (uint16_t) atoi(str.c_str());
>> +                update_latest_logid(*logid);
>> +                break;
>> +            }
>> +
>> +        } while( 1 );
>> +    } 
>> +    else
>> +    { 
>> +        cerr << "Error opening directory" << glogname << endl;
>> +        ent    = NULL;
>> +        *logid = 0;
>> +    }
>> +    return  ((ent == NULL) ? 0 : 1);
>> +}
>> +
>> +
>> +uint16_t message_create_new_log_event(event_record_t *rec) {
>> +
>> +    rec->logid = get_new_log_number();
>> +    return create_log_event(rec);
>> +}
>> diff --git a/message.H b/message.H
>> new file mode 100644
>> index 0000000..26ebe19
>> --- /dev/null
>> +++ b/message.H
>> @@ -0,0 +1,60 @@
>> +
>> +#include <dirent.h>
>> +#include <time.h>
>> +
>> +#ifdef __cplusplus
>> +    #include <cstdint>
>> +#else
>> +    #include <stdint.h>
>> +#endif
>> +
>> +
>> +#ifdef __cplusplus
>> +    struct event_log_list {
>> +#else
>> +    typedef struct _event_log_list {        
>> +#endif
>> +        DIR *dirp;
>> +#ifdef __cplusplus
>> +    };
>> +#else    
>> +    } event_log_list;
>> +#endif
>> +
>> +
>> +#ifdef __cplusplus
>> +    struct event_record_t {
>> +#else     
>> +    typedef struct _event_record_t {
>> +#endif
>> +        char *message;
>> +        char *severity;
>> +        char *association;
>> +        char *reportedby;
>> +        uint8_t *p;
>> +        size_t n;
>> +
>> +        // These get filled in for you
>> +        time_t  timestamp;        
>> +        int16_t logid;
>> +#ifdef __cplusplus
>> +    };
>> +#else     
>> +    } event_record_t;
>> +#endif
>> +
>> +
>> +#ifdef __cplusplus
>> +extern "C"  {
>> +#endif
>> +
>> +
>> +uint16_t message_create_new_log_event(event_record_t *rec);
>> +int      message_load_log(uint16_t logid, event_record_t **rec);
>> +void     message_free_log(event_record_t *rec);
>> +int      message_get_next_log(uint16_t *logid, event_log_list *log_list);
>> +int      message_delete_log(uint16_t logid);
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif
>> diff --git a/test.C b/test.C
>> new file mode 100644
>> index 0000000..afd834e
>> --- /dev/null
>> +++ b/test.C
>> @@ -0,0 +1,92 @@
>> +#include <iostream>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <stdint.h>
>> +
>> +#include "message.H"
>> +using namespace std;
>> +
>> +const char *glogname = "./events";
>> +
>> +#define ASSERT(a,b)  if(a!=b) {cout << "ASSERT ERROR: line " << __LINE__ << endl; exit(1);}
>> +
>> +void build_event_record(event_record_t *rec,
>> +						uint16_t logid,
>> +                        const char *message,
>> +                        const char *severity,
>> +                        const char *association,
>> +                        const char *reportedby,
>> +                        const uint8_t *p,
>> +                        size_t n) {
>> +
>> +
>> +    rec->message     = (char*) message;
>> +    rec->severity    = (char*) severity;
>> +    rec->association = (char*) association;
>> +    rec->reportedby  = (char*) reportedby;
>> +    rec->p           = (uint8_t*) p;
>> +    rec->n           = n;
>> +
>> +    return;
>> +}
>> +
>> +int load_existing_events(void) {
>> +
>> +	event_log_list log_list;
>> +	uint16_t       logid=0;
>> +	event_record_t *rec;
>> +
>> +	cout << "Loading event log... ";
>> +
>> +	while (message_get_next_log(&logid, &log_list)) {
>> +		cout << " " << int(logid);
>> +		message_load_log(logid, &rec);
>> +
>> +		cout << rec->message << endl;
>> +
>> +		message_free_log(rec);
>> +	}
>> +	cout << endl;
>> +	
>> +	return 0;
>> +}
>> +
>> +
>> +int main(int argc, char *argv[]) {
>> +
>> +	int rc = 0;
>> +
>> +	uint8_t p[] = {0x3, 0x32, 0x34, 0x36};
>> +	event_record_t rec, *prec;
>> +	event_log_list log_list;
>> +	uint16_t logid=0;
>> +	int i;
>> +
>> +	build_event_record(&rec,0, "Testing Message1", "Info", "Association", "Test", p, 4);
>> +	ASSERT(message_create_new_log_event(&rec),1);
>> +	build_event_record(&rec,0, "Testing Message2", "Info", "/dev", "Test", p, 4);
>> +	ASSERT(message_create_new_log_event(&rec),2);
>> +	build_event_record(&rec,0, "Testing Message3", "Info", "Association", "Test", p, 4);
>> +	ASSERT(message_create_new_log_event(&rec),3);
>> +
>> +	ASSERT(message_load_log(13, &prec), 0);
>> +	ASSERT(message_load_log(1, &prec), 1); message_free_log(prec);
>> +
>> +	// Test the number of valid logs so far
>> +	i = 0;
>> +	while (message_get_next_log(&logid, &log_list)) {
>> +
>> +
>> +		cout << int(logid) << endl;
>> +		i++;
>> +	}
>> +	//ASSERT(i,3);
>> +
>> +	cout << "LOADLOG TEST" << endl;
>> +
>> +	load_existing_events();
>> +
>> +	message_delete_log(1);
>> +
>> +	return rc;
>> +}
>> \ No newline at end of file
>> -- 
>> 2.6.4
>>
>>
>> _______________________________________________
>> openbmc mailing list
>> openbmc at lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/openbmc
> _______________________________________________
> openbmc mailing list
> openbmc at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/openbmc
>
>
> [attachment "signature.asc" removed by Chris Austen/Austin/IBM]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 859 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20160204/b677a56f/attachment-0001.sig>


More information about the openbmc mailing list