mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-23 05:57:33 +00:00
tools: acrn-crashlog: add sender telemd for acrnprobe
Sender telemd is responsible for sending log records to the telemetrics client. Signed-off-by: Liu Xinwu <xinwu.liu@intel.com> Reviewed-by: Zhang Yanmin <yanmin.zhang@intel.com> Reviewed-by: Liu Chuansheng <chuansheng.liu@intel.com> Reviewed-by: Zhao Yakui <yakui.zhao@intel.com> Reviewed-by: Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com> Acked-by: Eddie Dong <Eddie.dong@intel.com>
This commit is contained in:
parent
f83bd81645
commit
168d3ead00
@ -23,6 +23,17 @@
|
|||||||
#include "property.h"
|
#include "property.h"
|
||||||
#include "startupreason.h"
|
#include "startupreason.h"
|
||||||
#include "log_sys.h"
|
#include "log_sys.h"
|
||||||
|
#include "telemetry.h"
|
||||||
|
|
||||||
|
#define CRASH_SEVERITY 4
|
||||||
|
#define INFO_SEVERITY 2
|
||||||
|
|
||||||
|
struct telemd_data_t {
|
||||||
|
char *class;
|
||||||
|
char *srcdir;
|
||||||
|
char *eventid;
|
||||||
|
uint32_t severity;
|
||||||
|
};
|
||||||
|
|
||||||
/* get_log_file_* only used to copy regular file which can be mmaped */
|
/* get_log_file_* only used to copy regular file which can be mmaped */
|
||||||
static void get_log_file_complete(struct log_t *log, char *desdir)
|
static void get_log_file_complete(struct log_t *log, char *desdir)
|
||||||
@ -261,6 +272,124 @@ static void get_log_cmd(struct log_t *log, char *desdir)
|
|||||||
out_via_fork(log, desdir);
|
out_via_fork(log, desdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool telemd_send_data(char *payload, char *eventid, uint32_t severity,
|
||||||
|
char *class)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct telem_ref *handle = NULL;
|
||||||
|
const uint32_t version = 1;
|
||||||
|
|
||||||
|
res = tm_create_record(&handle, severity, class, version);
|
||||||
|
if (res < 0) {
|
||||||
|
LOGE("failed to create record: %s\n",
|
||||||
|
strerror(-res));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eventid with 32 character length */
|
||||||
|
if (eventid) {
|
||||||
|
res = tm_set_event_id(handle, eventid);
|
||||||
|
if (res < 0) {
|
||||||
|
LOGE("failed to set eventid: %s\n", strerror(-res));
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = tm_set_payload(handle, payload);
|
||||||
|
if (res < 0) {
|
||||||
|
LOGE("failed to set payload: %s\n", strerror(-res));
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = tm_send_record(handle);
|
||||||
|
if (res < 0) {
|
||||||
|
LOGE("failed to send record: %s\n", strerror(-res));
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
tm_free_record(handle);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
free:
|
||||||
|
tm_free_record(handle);
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telemd_get_log(struct log_t *log, void *data)
|
||||||
|
{
|
||||||
|
struct telemd_data_t *d = (struct telemd_data_t *)data;
|
||||||
|
char name[NAME_MAX];
|
||||||
|
char *path, *msg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (d->srcdir == NULL)
|
||||||
|
goto send_nologs;
|
||||||
|
|
||||||
|
ret = dir_contains(d->srcdir, log->name, 0, name);
|
||||||
|
if (ret == 1) {
|
||||||
|
ret = asprintf(&path, "%s/%s", d->srcdir, name);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
telemd_send_data(path, d->eventid, d->severity, d->class);
|
||||||
|
free(path);
|
||||||
|
} else if (ret == 0) {
|
||||||
|
LOGE("dir (%s) does not contains (%s)\n", d->srcdir,
|
||||||
|
log->name);
|
||||||
|
goto send_nologs;
|
||||||
|
} else if (ret > 1) {
|
||||||
|
/* got multiple files */
|
||||||
|
int i;
|
||||||
|
int count;
|
||||||
|
char *name;
|
||||||
|
char *files[512];
|
||||||
|
|
||||||
|
if (!strstr(log->path, ".[all]")) {
|
||||||
|
LOGE("dir (%s) contains (%d) files (%s)\n",
|
||||||
|
d->srcdir, ret, log->name);
|
||||||
|
goto send_nologs;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = lsdir(d->srcdir, files, ARRAY_SIZE(files));
|
||||||
|
if (count > 2) {
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
name = strrchr(files[i], '/') + 1;
|
||||||
|
if (!strstr(name, log->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
telemd_send_data(files[i], d->eventid,
|
||||||
|
d->severity, d->class);
|
||||||
|
}
|
||||||
|
} else if (count < 0) {
|
||||||
|
LOGE("lsdir (%s) failed, error (%s)\n", d->srcdir,
|
||||||
|
strerror(-count));
|
||||||
|
goto send_nologs;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0)
|
||||||
|
free(files[--count]);
|
||||||
|
} else {
|
||||||
|
LOGE("search (%s) in dir (%s) failed, error (%s)\n", log->name,
|
||||||
|
d->srcdir, strerror(-ret));
|
||||||
|
goto send_nologs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
send_nologs:
|
||||||
|
ret = asprintf(&msg, "no log generated on %s, check probe's log.",
|
||||||
|
log->name);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemd_send_data(msg, d->eventid, d->severity, d->class);
|
||||||
|
free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
static void crashlog_get_log(struct log_t *log, void *data)
|
static void crashlog_get_log(struct log_t *log, void *data)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -298,6 +427,354 @@ static void crashlog_get_log(struct log_t *log, void *data)
|
|||||||
LOGW("get (%s) spend %ds\n", log->name, spent);
|
LOGW("get (%s) spend %ds\n", log->name, spent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void telemd_send_crash(struct event_t *e)
|
||||||
|
{
|
||||||
|
struct crash_t *crash;
|
||||||
|
struct log_t *log;
|
||||||
|
char *class;
|
||||||
|
char *eventid;
|
||||||
|
int id;
|
||||||
|
int ret;
|
||||||
|
struct telemd_data_t data = {
|
||||||
|
.srcdir = e->dir,
|
||||||
|
.severity = CRASH_SEVERITY,
|
||||||
|
};
|
||||||
|
|
||||||
|
crash = (struct crash_t *)e->private;
|
||||||
|
|
||||||
|
ret = asprintf(&class, "clearlinux/crash/%s", crash->name);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventid = generate_eventid256(class);
|
||||||
|
if (eventid == NULL) {
|
||||||
|
LOGE("generate eventid failed, error (%s)\n", strerror(errno));
|
||||||
|
goto free_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.class = class;
|
||||||
|
data.eventid = eventid;
|
||||||
|
|
||||||
|
for_each_log_collect(id, log, crash) {
|
||||||
|
if (!log)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log->get(log, (void *)&data);
|
||||||
|
}
|
||||||
|
if (!strcmp(e->channel, "inotify")) {
|
||||||
|
char *des;
|
||||||
|
/* get the trigger file */
|
||||||
|
ret = asprintf(&des, "%s/%s", e->dir, e->path);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
goto free_eventid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists(des)) {
|
||||||
|
/* find the original path */
|
||||||
|
char *ori;
|
||||||
|
|
||||||
|
ret = asprintf(&ori, "%s/%s", crash->trigger->path,
|
||||||
|
e->path);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
free(des);
|
||||||
|
goto free_eventid;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGW("(%s) unavailable, try the original path (%s)\n",
|
||||||
|
des, ori);
|
||||||
|
if (!file_exists(ori)) {
|
||||||
|
LOGE("original path (%s) is unavailable\n",
|
||||||
|
ori);
|
||||||
|
} else {
|
||||||
|
telemd_send_data(ori, eventid, CRASH_SEVERITY,
|
||||||
|
class);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ori);
|
||||||
|
} else {
|
||||||
|
telemd_send_data(des, eventid, CRASH_SEVERITY, class);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(des);
|
||||||
|
}
|
||||||
|
free_eventid:
|
||||||
|
free(eventid);
|
||||||
|
free_class:
|
||||||
|
free(class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telemd_send_info(struct event_t *e)
|
||||||
|
{
|
||||||
|
struct info_t *info;
|
||||||
|
struct log_t *log;
|
||||||
|
char *class;
|
||||||
|
char *eventid;
|
||||||
|
int id;
|
||||||
|
int ret;
|
||||||
|
struct telemd_data_t data = {
|
||||||
|
.srcdir = e->dir,
|
||||||
|
.severity = INFO_SEVERITY,
|
||||||
|
};
|
||||||
|
|
||||||
|
info = (struct info_t *)e->private;
|
||||||
|
ret = asprintf(&class, "clearlinux/info/%s", info->name);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventid = generate_eventid256(class);
|
||||||
|
if (eventid == NULL) {
|
||||||
|
LOGE("generate eventid failed, error (%s)\n", strerror(errno));
|
||||||
|
goto free_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.class = class;
|
||||||
|
data.eventid = eventid;
|
||||||
|
|
||||||
|
for_each_log_collect(id, log, info) {
|
||||||
|
if (!log)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log->get(log, (void *)&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(eventid);
|
||||||
|
|
||||||
|
free_class:
|
||||||
|
free(class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telemd_send_uptime(void)
|
||||||
|
{
|
||||||
|
struct sender_t *telemd;
|
||||||
|
struct uptime_t *uptime;
|
||||||
|
char *class;
|
||||||
|
char boot_time[24];
|
||||||
|
int hours;
|
||||||
|
int ret;
|
||||||
|
static int uptime_hours;
|
||||||
|
static int loop_uptime_event = 1;
|
||||||
|
|
||||||
|
ret = get_uptime_string(boot_time, &hours);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("cannot get uptime - %s\n", strerror(-ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
telemd = get_sender_by_name("telemd");
|
||||||
|
uptime = telemd->uptime;
|
||||||
|
uptime_hours = atoi(uptime->eventhours);
|
||||||
|
if (hours / uptime_hours >= loop_uptime_event) {
|
||||||
|
char *content;
|
||||||
|
|
||||||
|
loop_uptime_event = (hours / uptime_hours) + 1;
|
||||||
|
ret = asprintf(&class, "clearlinux/uptime/%s", boot_time);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = asprintf(&content, "system boot time: %s", boot_time);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
free(class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemd_send_data(content, NULL, INFO_SEVERITY, class);
|
||||||
|
free(class);
|
||||||
|
free(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telemd_send_reboot(void)
|
||||||
|
{
|
||||||
|
struct sender_t *telemd;
|
||||||
|
char *class;
|
||||||
|
char reason[MAXLINESIZE];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
telemd = get_sender_by_name("telemd");
|
||||||
|
if (swupdated(telemd)) {
|
||||||
|
char *content;
|
||||||
|
|
||||||
|
ret = asprintf(&class, "clearlinux/swupdate/-");
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = asprintf(&content, "system update to: %s",
|
||||||
|
gbuildversion);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
free(class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemd_send_data(content, NULL, INFO_SEVERITY, class);
|
||||||
|
free(class);
|
||||||
|
free(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
read_startupreason(reason);
|
||||||
|
ret = asprintf(&class, "clearlinux/reboot/%s", reason);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemd_send_data("reboot", NULL, INFO_SEVERITY, class);
|
||||||
|
free(class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telemd_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||||
|
{
|
||||||
|
char event[96] = {0};
|
||||||
|
char longtime[96] = {0};
|
||||||
|
char type[96] = {0};
|
||||||
|
char rest[PATH_MAX] = {0};
|
||||||
|
char *vmlogpath[1] = {0};
|
||||||
|
char vmkey[SHA_DIGEST_LENGTH + 1] = {0};
|
||||||
|
char *log;
|
||||||
|
char *class;
|
||||||
|
char *eventid;
|
||||||
|
char *files[512];
|
||||||
|
int count;
|
||||||
|
int i;
|
||||||
|
uint32_t severity;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* VM events in history_event look like this:
|
||||||
|
*
|
||||||
|
* "CRASH xxxxxxxxxxxxxxxxxxxx 2017-11-11/03:12:59 JAVACRASH
|
||||||
|
* /data/logs/crashlog0_xxxxxxxxxxxxxxxxxxxx"
|
||||||
|
* "REBOOT xxxxxxxxxxxxxxxxxxxx 2011-11-11/11:20:51 POWER-ON
|
||||||
|
* 0000:00:00"
|
||||||
|
*/
|
||||||
|
char *vm_format = "%[^ ]%*[ ]%[^ ]%*[ ]%[^ ]%*[ ]%[^ ]%*[ ]%[^\n]%*c";
|
||||||
|
|
||||||
|
ret = sscanf(line_to_sync, vm_format, event, vmkey, longtime,
|
||||||
|
type, rest);
|
||||||
|
if (ret != 5) {
|
||||||
|
LOGE("get a invalied line from (%s), skip\n", vm->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(event, "CRASH") == 0)
|
||||||
|
severity = CRASH_SEVERITY;
|
||||||
|
else
|
||||||
|
severity = INFO_SEVERITY;
|
||||||
|
|
||||||
|
/* if line contains log, fill vmlogpath */
|
||||||
|
log = strstr(rest, "/logs/");
|
||||||
|
if (log) {
|
||||||
|
struct sender_t *crashlog = get_sender_by_name("crashlog");
|
||||||
|
|
||||||
|
ret = find_file(crashlog->outdir, log + strlen("/logs/"),
|
||||||
|
2, vmlogpath, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("find (%s) in (%s) failed, strerror (%s)\n",
|
||||||
|
log + strlen("/logs/"), crashlog->outdir,
|
||||||
|
strerror(-ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = asprintf(&class, "%s/%s/%s", vm->name, event, type);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
goto free_vmlogpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventid = generate_eventid256(class);
|
||||||
|
if (eventid == NULL) {
|
||||||
|
LOGE("generate eventid failed, error (%s)\n", strerror(errno));
|
||||||
|
goto free_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vmlogpath[0] == 0) {
|
||||||
|
telemd_send_data("no logs", eventid, severity, class);
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send logs */
|
||||||
|
count = lsdir(vmlogpath[0], files, ARRAY_SIZE(files));
|
||||||
|
if (count > 2) {
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (!strstr(files[i], "/.") &&
|
||||||
|
!strstr(files[i], "/.."))
|
||||||
|
telemd_send_data(files[i], eventid, severity,
|
||||||
|
class);
|
||||||
|
}
|
||||||
|
} else if (count == 2) {
|
||||||
|
char *content;
|
||||||
|
|
||||||
|
ret = asprintf(&content, "no logs under (%s)", vmlogpath[0]);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("compute string failed, out of memory\n");
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemd_send_data(content, eventid, severity, class);
|
||||||
|
free(content);
|
||||||
|
} else if (count < 0) {
|
||||||
|
LOGE("lsdir (%s) failed, error (%s)\n", vmlogpath[0],
|
||||||
|
strerror(-count));
|
||||||
|
} else {
|
||||||
|
LOGE("get (%d) files in (%s) ???\n", count, vmlogpath[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0)
|
||||||
|
free(files[--count]);
|
||||||
|
|
||||||
|
free:
|
||||||
|
free(eventid);
|
||||||
|
free_class:
|
||||||
|
free(class);
|
||||||
|
free_vmlogpath:
|
||||||
|
if (vmlogpath[0])
|
||||||
|
free(vmlogpath[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telemd_send(struct event_t *e)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
struct log_t *log;
|
||||||
|
|
||||||
|
for_each_log(id, log, conf) {
|
||||||
|
if (!log)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log->get = telemd_get_log;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (e->event_type) {
|
||||||
|
case CRASH:
|
||||||
|
telemd_send_crash(e);
|
||||||
|
break;
|
||||||
|
case INFO:
|
||||||
|
telemd_send_info(e);
|
||||||
|
break;
|
||||||
|
case UPTIME:
|
||||||
|
telemd_send_uptime();
|
||||||
|
break;
|
||||||
|
case REBOOT:
|
||||||
|
telemd_send_reboot();
|
||||||
|
break;
|
||||||
|
case VM:
|
||||||
|
refresh_vm_history(get_sender_by_name("telemd"),
|
||||||
|
telemd_new_vmevent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGE("unsupoorted event type %d\n", e->event_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void crashlog_send_crash(struct event_t *e)
|
static void crashlog_send_crash(struct event_t *e)
|
||||||
{
|
{
|
||||||
struct crash_t *crash;
|
struct crash_t *crash;
|
||||||
@ -645,6 +1122,9 @@ int init_sender(void)
|
|||||||
ret = prepare_history();
|
ret = prepare_history();
|
||||||
if (ret)
|
if (ret)
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (!strncmp(sender->name, "telemd",
|
||||||
|
strlen(sender->name))) {
|
||||||
|
sender->send = telemd_send;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user