Monday, March 22, 2010

Sun Cluster Eventlogd

The eventlogd log files are kept in /var/cluster/logs ( eventlog*) in binary format however, this isn't terribly accessible for admins ( unless you're going to use 'strings' or 'od')

I did come across an application called 'showev4' which does a nice formatted dump of this file, however it's not released by sun and I really had no idea what it was doing as I haven't been able to find the source. So, here's more or less what it does:

Basically, each log entry is made up of a structure like this:

length - length of the entry
nvlist_t event - an nvlist_t of the event which includes the pid, vendor, cluster class etc..
nvlist_t attributes - another nvlist_t which contains the important information regarding the event. eg. command run, who ran it, when they ran it, which resources it affected etc.

Analysing the eventlog source code, I knocked up this C application which will extract relevant event information from this log file. Note: this is not designed to show you _everything_, just what I considered important.


/*
* gcc -Wall -g show_eventlog.c -lnvpair -lsysevent
*/

/* sorry about the syntax errors here, blogger doesn't like includes */
#include stdio.h
#include time.h
#include string.h
#include stdlib.h
#include unistd.h
#include libnvpair.h
#include libsysevent.h

/* Event details */
#define CL_CLASS_NAME "ev_class"
#define CL_SUBCLASS_NAME "ev_subclass"
#define CL_VENDOR "ev_vendor"
#define CL_PID "ev_pid"
#define CL_DATA "ev_data"
#define CL_PUB "ev_pub"

/* event properties
* some of the following definitions are
* taken from :
* /usr/src/common/cl/sys/cl_eventdefs.h
* Note: Not all event properties will exist
* for every event
*/

#define CL_CLUSTER_NAME "ev_cluster_name"
#define CL_CLUSTER_ID "ev_cluster_id"
#define CL_EVENT_NODE "ev_node_name"
#define CL_EVENT_TS_SEC "ev_ts_sec"
#define CL_EVENT_TS_USEC "ev_ts_usec"
#define CL_EVENT_RESOURCE "r_name"
#define CL_EVENT_RG "rg_name"
#define CL_EVENT_TS_USEC "ev_ts_usec"
#define CL_EVENT_INITIATOR "ev_initiator"
#define CL_EVENT_SEVERITY "ev_severity"
#define CL_EVENT_BROADCAST "ev_broadcast"
#define CL_EVENT_VERSION "ev_version"
#define CL_EVENT_VERSION_NUMBER 2
#define CL_EVENT_PUB_RGM "rgm"
#define CL_EVENT_PUB_PMF "pmf"
#define CL_EVENT_PUB_CMM "cmm"
#define CL_EVENT_PUB_NET "net"
#define CL_EVENT_PUB_DCS "dcs"
#define CL_EVENT_PUB_DPM "dpm"
#define CL_EVENT_PUB_TP "tp"
#define CL_EVENT_PUB_UCMM "ucmm"
#define CL_EVENT_PUB_GDS "gds"
#define CL_EVENT_PUB_CMD_START "cmd_start"
#define CL_EVENT_PUB_CMD_END "cmd_end"
#define CL_EVENT_PUB_ZONES "sc_zones"
#define CL_EVENT_PUB_SLM "slm"
#define CL_EVENT_PUB_FMM "fmm"
#define CL_EVENT_PUB_HBR "hbr"
#define CL_EVENT_PUB_CMD "cmd"
#define CL_EVENT_CMD_UID "cmd_uid"
#define CL_EVENT_CMD_EUID "cmd_euid"
#define CL_EVENT_CMD_LOGIN "cmd_login"
#define CL_EVENT_CMD_TTY_STDIN "cmd_tty_stdin"
#define CL_EVENT_CMD_TTY_STDOUT "cmd_tty_stdout"
#define CL_EVENT_CMD_PID "cmd_pid"
#define CL_EVENT_CMD_PPID "cmd_ppid"
#define CL_EVENT_CMD_NAME "cmd_name"
#define CL_EVENT_CMD_OPT "cmd_opt"
#define CL_EVENT_CMD_RES "cmd_res"
#define CL_EVENT_ZONE_STATE "zone_state"
#define CL_EVENT_ZONE_NAME "zone_name"
#define CL_EVENT_STATE_LIST "state_list"
#define CL_EVENT_OLD_STATUS "old_status"
#define CL_EVENT_NEW_STATUS "new_status"


char * get_string( const char *string, nvlist_t *vlist);
uint32_t get_uint ( const char *string, nvlist_t *nvl );
void get_attr( const char *string, nvlist_t *nvl);
void get_data(nvlist_t *nvl);
void output ( const char *s1, const char *s2 );

int main( int argc, char **argv) {

FILE *file;
int size;

char *name="/var/cluster/logs/eventlog";

char *buffer;

nvlist_t *nvl = NULL;
int err;

if ( argc >1 )
{
name=argv[1];
}


//Open file
file = fopen(name, "rb");
if (!file)
{
fprintf(stderr, "Unable to open file %s", name);
return 1;
}

while (file)
{
if(!fread(&size,4,1,file))
{
return 0;
}


buffer=(char *)malloc(size);
memset(buffer,'\0',sizeof(buffer));

if ( !buffer)
{
printf("Could not allocate memory\n");
return 1;
}
fread(buffer,size,1,file);

err=nvlist_unpack(buffer,size,&nvl,0);
if (err)
{
printf("nvlist failed to unpack: %s\n",strerror(err));
return 1;
}
get_data(nvl);
}


return 0;
}

/*
* Grab event data
*/
void get_data(nvlist_t *nvl)
{

get_attr(CL_DATA,nvl);
output(" ",get_string(CL_CLASS_NAME,nvl));
output("::",get_string(CL_SUBCLASS_NAME,nvl));
printf("\n");
}

/*
* use nvlist_lookup_string to get string from
* specified nvlist_t
*/
char * get_string ( const char *string, nvlist_t *nvl)
{
int err;
char *val;

err = nvlist_lookup_string(nvl,string,&val);
if ( err )
{
// printf("string %s not found",string);
return "";
}
else
{
// printf(" %s\t",val);
return val;
}
}

/*
* use nvlist_lookup_uint32 to get unsigned int from
* specified nvlist_t
*/
uint32_t get_uint ( const char *string, nvlist_t *nvl)
{
int err;
uint32_t val;

err = nvlist_lookup_uint32(nvl,string,&val);
if ( err )
{
// printf("string %s not found",string);
return 0;
}
else
{
// printf(" %d\t",val);
return val;
}
}

/*
* get attributes from event attribute nvlist_t
*
*/
void get_attr( const char *string, nvlist_t *nvl)
{
int err;
uchar_t *val=NULL;
uint_t count;
nvlist_t *nvlist=NULL;

struct timeval timestamp;
struct tm *time_fields = NULL;

count=0;

err=nvlist_lookup_byte_array(nvl,"ev_data",&val,&count);
if ( err )
{
// printf("string %s not found", string);
}
else
{
err=nvlist_unpack(val,count,&nvlist,0);
if (err)
{
printf("nvlist failed to unpack: %s\n",strerror(err));
return ;
}

timestamp.tv_sec=get_uint(CL_EVENT_TS_SEC,nvlist);
time_fields=localtime((time_t *) &timestamp.tv_sec);

printf("%02d/%02d/%04d %02d:%02d:%02d ",
time_fields->tm_mday, time_fields->tm_mon+1,
time_fields->tm_year+1900, time_fields->tm_hour,
time_fields->tm_min, time_fields->tm_sec);


output(" ",get_string(CL_EVENT_NODE, nvlist ));
output(" ",get_string(CL_EVENT_ZONE_NAME, nvlist ));
output(" ",get_string(CL_CLUSTER_NAME, nvlist ));
output(" ",get_string(CL_EVENT_CMD_RES, nvlist ));
output(" ",get_string(CL_EVENT_CMD_NAME, nvlist ));
output(" ",get_string(CL_EVENT_CMD_OPT, nvlist ));
output(" ",get_string(CL_EVENT_ZONE_NAME, nvlist ));
output(" ",get_string(CL_EVENT_CMD_LOGIN, nvlist ));
output(" ",get_string(CL_EVENT_RESOURCE, nvlist ));
output(" ",get_string(CL_EVENT_RG, nvlist ));
output(" ",get_string(CL_EVENT_STATE_LIST, nvlist ));
output(" ",get_string(CL_EVENT_OLD_STATUS, nvlist ));
output("->",get_string(CL_EVENT_NEW_STATUS, nvlist ));

}
}

/* print output ( two strings are required */
void output ( const char *s1, const char *s2 )
{
if ( s1 && s2 )
{
if ( strlen(s1) > 0 && strlen(s2) > 0 )
{
printf( "%s%s", s1, s2 );
}
}
}

1 comment:

Jens Nickel said...

brilliant code thank you very much