launch_daemon: Added basic logging facility
* The daemon now stores many events in am internal log. * You can use "launch_roster log" to retrieve it.
This commit is contained in:
+137
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016, Axel Dörfler, [email protected].
|
||||
* Copyright 2015-2018, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
#include <LaunchRoster.h>
|
||||
#include <StringList.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
static struct option const kLongOptions[] = {
|
||||
@@ -23,6 +24,16 @@ static struct option const kLongOptions[] = {
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static struct option const kLogLongOptions[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"raw", no_argument, 0, 'r'},
|
||||
{"user", no_argument, 0, 'u'},
|
||||
{"system", no_argument, 0, 's'},
|
||||
{"event", required_argument, 0, 'e'},
|
||||
{"limit", required_argument, 0, 'l'},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
extern const char *__progname;
|
||||
static const char *kProgramName = __progname;
|
||||
|
||||
@@ -61,6 +72,127 @@ list_targets(bool verbose)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_log(const BMessage& log)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
bigtime_t runtime = system_time();
|
||||
|
||||
for (int32 index = 0;; index++) {
|
||||
BMessage item;
|
||||
if (log.FindMessage("item", index, &item) != B_OK)
|
||||
break;
|
||||
|
||||
uint64 when;
|
||||
const char* message;
|
||||
if (item.FindUInt64("when", &when) != B_OK
|
||||
|| item.FindString("message", &message) != B_OK)
|
||||
break;
|
||||
|
||||
time_t at = now - (runtime - when) / 1000000l;
|
||||
struct tm tm;
|
||||
localtime_r(&at, &tm);
|
||||
char label[256];
|
||||
strftime(label, sizeof(label), "%F %X", &tm);
|
||||
printf("%s %s\n", label, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
log_usage(int status)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s log [-rusel] [<job-name>]\n"
|
||||
"Where the following options are allowed:\n"
|
||||
" -u --user List only user log entries\n"
|
||||
" -s --system List only system log entries\n"
|
||||
" -e --event Filter by event name (partial names accepted)\n"
|
||||
" -l --limit <n> Limit output to <n> events\n"
|
||||
"<job-name>, if given, filters the jobs by name.\n",
|
||||
kProgramName);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_log(int argCount, char** args)
|
||||
{
|
||||
bool raw = false;
|
||||
bool userOnly = false;
|
||||
bool systemOnly = false;
|
||||
int32 limit = 0;
|
||||
const char* event = NULL;
|
||||
const char* job = NULL;
|
||||
|
||||
optind = 0;
|
||||
int c;
|
||||
while ((c = getopt_long(argCount, args, "hruse:l:", kLogLongOptions, NULL))
|
||||
!= -1) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
break;
|
||||
case 'h':
|
||||
log_usage(0);
|
||||
break;
|
||||
case 'r':
|
||||
raw = true;
|
||||
break;
|
||||
case 'u':
|
||||
userOnly = true;
|
||||
break;
|
||||
case 's':
|
||||
systemOnly = true;
|
||||
break;
|
||||
case 'e':
|
||||
event = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
limit = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argCount - optind >= 1)
|
||||
job = args[optind];
|
||||
|
||||
BLaunchRoster roster;
|
||||
BMessage filter;
|
||||
if (userOnly)
|
||||
filter.AddBool("userOnly", true);
|
||||
if (systemOnly)
|
||||
filter.AddBool("systemOnly", true);
|
||||
if (event != NULL)
|
||||
filter.AddString("event", event);
|
||||
if (job != NULL)
|
||||
filter.AddString("job", job);
|
||||
if (limit != 0)
|
||||
filter.AddInt32("limit", limit);
|
||||
|
||||
BMessage info;
|
||||
status_t status = roster.GetLog(filter, info);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "%s: Could not get log: %s\n", kProgramName,
|
||||
strerror(status));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (raw) {
|
||||
info.PrintToStream();
|
||||
return;
|
||||
}
|
||||
|
||||
print_log(info);
|
||||
|
||||
BMessage user;
|
||||
if (info.FindMessage("user", &user) == B_OK) {
|
||||
if (user.HasMessage("item"))
|
||||
puts("User log:");
|
||||
print_log(user);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_info(const char* name)
|
||||
{
|
||||
@@ -165,7 +297,7 @@ main(int argc, char** argv)
|
||||
bool verbose = false;
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "hv", kLongOptions, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "+hv", kLongOptions, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
break;
|
||||
@@ -188,6 +320,8 @@ main(int argc, char** argv)
|
||||
list_jobs(verbose);
|
||||
} else if (strcmp(command, "list-targets") == 0) {
|
||||
list_targets(verbose);
|
||||
} else if (strcmp(command, "log") == 0) {
|
||||
get_log(argc - optind, &argv[optind]);
|
||||
} else if (argc == optind + 1) {
|
||||
// For convenience (the "info" command can be omitted)
|
||||
get_info(command);
|
||||
|
||||
Reference in New Issue
Block a user