[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