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:
Axel Dörfler 2018-04-25 09:18:34 +02:00
parent 6d7b8a3088
commit a77aa747ea
13 changed files with 1227 additions and 33 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015-2017, Haiku, Inc. All Rights Reserved.
* Copyright 2015-2018, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -45,6 +45,7 @@ enum {
B_GET_LAUNCH_JOBS = 'lngj',
B_GET_LAUNCH_TARGET_INFO = 'lntI',
B_GET_LAUNCH_JOB_INFO = 'lnjI',
B_GET_LAUNCH_LOG = 'lnLL',
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015-2016 Haiku, Inc. All rights reserved.
* Copyright 2015-2018 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _LAUNCH_ROSTER_H
@ -56,6 +56,9 @@ public:
status_t GetJobs(const char* target, BStringList& jobs);
status_t GetJobInfo(const char* name, BMessage& info);
status_t GetLog(BMessage& info);
status_t GetLog(const BMessage& filter, BMessage& info);
class Private;
private:
@ -70,6 +73,7 @@ private:
uint32 flags = 0);
status_t _GetInfo(uint32 what, const char* name,
BMessage& info);
status_t _GetLog(const BMessage* filter, BMessage& info);
private:
BMessenger fMessenger;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015-2016, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
* 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);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015-2016 Haiku, Inc. All rights reserved.
* Copyright 2015-2017 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -338,6 +338,20 @@ BLaunchRoster::GetJobInfo(const char* name, BMessage& info)
}
status_t
BLaunchRoster::GetLog(BMessage& info)
{
return _GetLog(NULL, info);
}
status_t
BLaunchRoster::GetLog(const BMessage& filter, BMessage& info)
{
return _GetLog(&filter, info);
}
void
BLaunchRoster::_InitMessenger()
{
@ -414,3 +428,17 @@ BLaunchRoster::_GetInfo(uint32 what, const char* name, BMessage& info)
return _SendRequest(request, info);
}
status_t
BLaunchRoster::_GetLog(const BMessage* filter, BMessage& info)
{
BMessage request(B_GET_LAUNCH_LOG);
status_t status = request.AddInt32("user", getuid());
if (status == B_OK && filter != NULL)
status = request.AddMessage("filter", filter);
if (status != B_OK)
return status;
return _SendRequest(request, info);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -39,7 +39,7 @@ public:
virtual status_t Register(EventRegistrator& registrator);
virtual void Unregister(EventRegistrator& registrator);
virtual void Trigger();
virtual void Trigger(Event* origin);
virtual BaseJob* Owner() const;
virtual void SetOwner(BaseJob* owner);
@ -205,11 +205,11 @@ Event::Triggered() const
void
Event::Trigger()
Event::Trigger(Event* origin)
{
fTriggered = true;
if (fParent != NULL)
fParent->Trigger();
fParent->Trigger(origin);
}
@ -336,12 +336,13 @@ EventContainer::Unregister(EventRegistrator& registrator)
void
EventContainer::Trigger()
EventContainer::Trigger(Event* origin)
{
Event::Trigger();
Event::Trigger(origin);
if (Parent() == NULL && Owner() != NULL) {
BMessage message(kMsgEventTriggered);
message.AddPointer("event", origin);
message.AddString("owner", Owner()->Name());
fTarget.SendMessage(&message);
}
@ -620,7 +621,7 @@ VolumeMountedEvent::ToString() const
void
VolumeMountedEvent::VolumeMounted(dev_t device)
{
Trigger();
Trigger(this);
}
@ -667,7 +668,7 @@ void
NetworkAvailableEvent::NetworkAvailabilityChanged(bool available)
{
if (available)
Trigger();
Trigger(this);
else
ResetSticky();
}
@ -737,7 +738,7 @@ Events::TriggerExternalEvent(Event* event, const char* name)
Event* event = container->Events().ItemAt(index);
if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
if (external->Name() == name) {
external->Trigger();
external->Trigger(container);
return;
}
} else if (dynamic_cast<EventContainer*>(event) != NULL) {
@ -794,7 +795,7 @@ Events::TriggerDemand(Event* event, bool testOnly)
if (testOnly)
return true;
childEvent->Trigger();
childEvent->Trigger(childEvent);
break;
}
if (dynamic_cast<EventContainer*>(childEvent) != NULL) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef EVENTS_H
@ -35,7 +35,7 @@ public:
EventRegistrator& registrator) = 0;
bool Triggered() const;
virtual void Trigger();
virtual void Trigger(Event* origin);
virtual void ResetTrigger();
virtual BaseJob* Owner() const;

View File

@ -1,6 +1,6 @@
SubDir HAIKU_TOP src servers launch ;
UsePrivateHeaders app libroot shared storage support ;
UsePrivateHeaders app kernel libroot shared storage support ;
UsePrivateSystemHeaders ;
UseHeaders [ FDirName $(HAIKU_TOP) src bin multiuser ] ;
@ -13,6 +13,7 @@ Server launch_daemon
Conditions.cpp
Events.cpp
Job.cpp
Log.cpp
NetworkWatcher.cpp
SettingsParser.cpp
Target.cpp

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015-2016, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -34,7 +34,8 @@ Job::Job(const char* name)
fToken((uint32)B_PREFERRED_TOKEN),
fLaunchStatus(B_NO_INIT),
fTarget(NULL),
fPendingLaunchDataReplies(0, false)
fPendingLaunchDataReplies(0, false),
fTeamListener(NULL)
{
mutex_init(&fLaunchStatusLock, "launch status lock");
}
@ -694,7 +695,7 @@ Job::_Launch(const char* signature, entry_ref* ref, int argCount,
resume_thread(mainThread);
if (fTeamListener != NULL)
fTeamListener->TeamLaunched(this);
fTeamListener->TeamLaunched(this, result);
} else
kill_thread(mainThread);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef JOB_H
@ -34,7 +34,7 @@ typedef std::map<BString, BMessage> PortMap;
class TeamListener {
public:
virtual void TeamLaunched(Job* job) = 0;
virtual void TeamLaunched(Job* job, status_t status) = 0;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015-2017, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -41,6 +41,7 @@
#include "InitSharedMemoryDirectoryJob.h"
#include "InitTemporaryDirectoryJob.h"
#include "Job.h"
#include "Log.h"
#include "SettingsParser.h"
#include "Target.h"
#include "Utility.h"
@ -147,7 +148,7 @@ public:
const char* name);
// TeamListener
virtual void TeamListener(Job* job);
virtual void TeamLaunched(Job* job, status_t status);
virtual void ReadyToRun();
virtual void MessageReceived(BMessage* message);
@ -170,6 +171,7 @@ private:
void _HandleGetLaunchTargetInfo(BMessage* message);
void _HandleGetLaunchJobs(BMessage* message);
void _HandleGetLaunchJobInfo(BMessage* message);
void _HandleGetLaunchLog(BMessage* message);
uid_t _GetUserID(BMessage* message);
void _ReadPaths(const BStringList& paths);
@ -222,6 +224,7 @@ private:
void _AddInitJob(BJob* job);
private:
Log fLog;
JobMap fJobs;
TargetMap fTargets;
BStringList fRunTargets;
@ -425,8 +428,10 @@ LaunchDaemon::UnregisterExternalEvent(Event* event, const char* name)
void
LaunchDaemon::RegisterTeam(Job* job)
LaunchDaemon::TeamLaunched(Job* job, status_t status)
{
fLog.JobLaunched(job, status);
MutexLocker locker(fTeamsLock);
fTeams.insert(std::make_pair(job->Team(), job));
}
@ -514,6 +519,11 @@ LaunchDaemon::MessageReceived(BMessage* message)
if (found != fTeams.end()) {
Job* job = found->second;
TRACE("Job %s ended!\n", job->Name());
// Get the exit status, and pass it on to the log
status_t exitStatus = B_OK;
wait_for_thread(team, &exitStatus);
fLog.JobTerminated(job, exitStatus);
job->TeamDeleted();
if (job->IsService()) {
@ -613,22 +623,30 @@ LaunchDaemon::MessageReceived(BMessage* message)
_HandleGetLaunchJobInfo(message);
break;
case B_GET_LAUNCH_LOG:
_HandleGetLaunchLog(message);
break;
case kMsgEventTriggered:
{
// An internal event has been triggered.
// Check if its job can be launched now.
// Check if its job(s) can be launched now.
const char* name = message->GetString("owner");
if (name == NULL)
break;
Event* event = (Event*)message->GetPointer("event");
Job* job = FindJob(name);
if (job != NULL) {
fLog.EventTriggered(job, event);
_LaunchJob(job);
break;
}
Target* target = FindTarget(name);
if (target != NULL) {
fLog.EventTriggered(target, event);
_LaunchJobs(target);
break;
}
@ -785,7 +803,9 @@ LaunchDaemon::_HandleStopLaunchTarget(BMessage* message)
if (message->FindMessage("data", &data) == B_OK)
target->AddData(data.GetString("name"), data);
_StopJobs(target, message->GetBool("force"));
bool force = message->GetBool("force");
fLog.JobStopped(target, force);
_StopJobs(target, force);
BMessage reply((uint32)B_OK);
message->SendReply(&reply);
@ -848,6 +868,7 @@ LaunchDaemon::_HandleEnableLaunchJob(BMessage* message)
}
job->SetEnabled(enable);
fLog.JobEnabled(job, enable);
BMessage reply((uint32)B_OK);
message->SendReply(&reply);
@ -877,7 +898,9 @@ LaunchDaemon::_HandleStopLaunchJob(BMessage* message)
return;
}
_StopJob(job, message->GetBool("force"));
bool force = message->GetBool("force");
fLog.JobStopped(job, force);
_StopJob(job, force);
BMessage reply((uint32)B_OK);
message->SendReply(&reply);
@ -965,6 +988,8 @@ LaunchDaemon::_HandleRegisterLaunchEvent(BMessage* message)
eventName.Prepend(ownerName);
fEvents.insert(std::make_pair(eventName, event));
_ResolveExternalEvents(event, eventName);
fLog.ExternalEventRegistered(name);
} else
status = B_NO_MEMORY;
} else
@ -1002,6 +1027,8 @@ LaunchDaemon::_HandleUnregisterLaunchEvent(BMessage* message)
eventName.Prepend("/");
eventName.Prepend(ownerName);
fEvents.erase(eventName);
fLog.ExternalEventRegistered(name);
} else
status = B_BAD_VALUE;
@ -1028,6 +1055,8 @@ LaunchDaemon::_HandleNotifyLaunchEvent(BMessage* message)
ExternalEventSource* event = _FindEvent(ownerName, name);
if (event != NULL) {
fLog.ExternalEventTriggered(name);
// Evaluate all of its jobs
int32 count = event->CountListeners();
for (int32 index = 0; index < count; index++) {
@ -1223,6 +1252,90 @@ LaunchDaemon::_HandleGetLaunchJobInfo(BMessage* message)
}
void
LaunchDaemon::_HandleGetLaunchLog(BMessage* message)
{
uid_t user = _GetUserID(message);
if (user < 0)
return;
BMessage filter;
BString jobName;
const char* event = NULL;
int32 limit = 0;
bool systemOnly = false;
bool userOnly = false;
if (message->FindMessage("filter", &filter) == B_OK) {
limit = filter.GetInt32("limit", 0);
jobName = filter.GetString("job");
jobName.ToLower();
event = filter.GetString("event");
systemOnly = filter.GetBool("systemOnly");
userOnly = filter.GetBool("userOnly");
}
BMessage info((uint32)B_OK);
int32 count = 0;
if (user == 0 || !userOnly) {
LogItemList::Iterator iterator = fLog.Iterator();
while (iterator.HasNext()) {
LogItem* item = iterator.Next();
if (!item->Matches(jobName.IsEmpty() ? NULL : jobName.String(),
event)) {
continue;
}
BMessage itemMessage;
itemMessage.AddUInt64("when", item->When());
itemMessage.AddInt32("type", (int32)item->Type());
itemMessage.AddString("message", item->Message());
BMessage parameter;
item->GetParameter(parameter);
itemMessage.AddMessage("parameter", &parameter);
info.AddMessage("item", &itemMessage);
// limit == 0 means no limit
if (++count == limit)
break;
}
}
// Get the list from the user daemon, and merge it into our reply
Session* session = FindSession(user);
if (session != NULL && !systemOnly) {
if (limit != 0) {
// Update limit for user daemon
limit -= count;
if (limit <= 0) {
message->SendReply(&info);
return;
}
}
BMessage reply;
BMessage request(B_GET_LAUNCH_LOG);
status_t status = request.AddInt32("user", 0);
if (status == B_OK && (limit != 0 || !jobName.IsEmpty()
|| event != NULL)) {
// Forward filter specification when needed
status = filter.SetInt32("limit", limit);
if (status == B_OK)
status = request.AddMessage("filter", &filter);
}
if (status == B_OK)
status = session->Daemon().SendMessage(&request, &reply);
if (status == B_OK)
info.AddMessage("user", &reply);
}
message->SendReply(&info);
}
uid_t
LaunchDaemon::_GetUserID(BMessage* message)
{
@ -1419,8 +1532,10 @@ LaunchDaemon::_AddJob(Target* target, bool service, BMessage& message)
} else
TRACE(" amend job \"%s\"\n", name.String());
if (message.HasBool("disabled"))
if (message.HasBool("disabled")) {
job->SetEnabled(!message.GetBool("disabled", !job->IsEnabled()));
fLog.JobEnabled(job, job->IsEnabled());
}
if (message.HasBool("legacy"))
job->SetCreateDefaultPort(!message.GetBool("legacy", !service));
@ -1477,12 +1592,15 @@ LaunchDaemon::_InitJobs(Target* target)
}
}
if (status != B_OK) {
if (status == B_OK) {
fLog.JobInitialized(job);
} else {
if (status != B_NO_INIT) {
// TODO: log error
debug_printf("Init \"%s\" failed: %s\n", job->Name(),
strerror(status));
}
fLog.JobIgnored(job, status);
// Remove jobs that won't be used later on
fJobs.erase(remove);

810
src/servers/launch/Log.cpp Normal file
View File

@ -0,0 +1,810 @@
/*
* Copyright 2017-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "Log.h"
#include <OS.h>
#include "Events.h"
#include "Job.h"
const size_t kMaxItems = 10000;
class AbstractJobLogItem : public LogItem {
public:
AbstractJobLogItem(BaseJob* job);
virtual ~AbstractJobLogItem();
virtual status_t GetParameter(BMessage& parameter) const;
virtual bool Matches(const char* jobName,
const char* eventName);
protected:
BaseJob* fJob;
};
class JobInitializedLogItem : public AbstractJobLogItem {
public:
JobInitializedLogItem(Job* job);
virtual ~JobInitializedLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
};
class JobIgnoredLogItem : public LogItem {
public:
JobIgnoredLogItem(Job* job, status_t error);
virtual ~JobIgnoredLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
virtual status_t GetParameter(BMessage& parameter) const;
virtual bool Matches(const char* jobName,
const char* eventName);
private:
BString fJobName;
status_t fError;
};
class JobLaunchedLogItem : public AbstractJobLogItem {
public:
JobLaunchedLogItem(Job* job, status_t status);
virtual ~JobLaunchedLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
virtual status_t GetParameter(BMessage& parameter) const;
private:
status_t fStatus;
};
class JobTerminatedLogItem : public AbstractJobLogItem {
public:
JobTerminatedLogItem(Job* job, status_t status);
virtual ~JobTerminatedLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
virtual status_t GetParameter(BMessage& parameter) const;
private:
status_t fStatus;
};
class JobEnabledLogItem : public AbstractJobLogItem {
public:
JobEnabledLogItem(Job* job, bool enabled);
virtual ~JobEnabledLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
virtual status_t GetParameter(BMessage& parameter) const;
private:
bool fEnabled;
};
class JobStoppedLogItem : public AbstractJobLogItem {
public:
JobStoppedLogItem(BaseJob* job, bool force);
virtual ~JobStoppedLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
virtual status_t GetParameter(BMessage& parameter) const;
private:
bool fForce;
};
class EventLogItem : public AbstractJobLogItem {
public:
EventLogItem(BaseJob* job, Event* event);
virtual ~EventLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
virtual status_t GetParameter(BMessage& parameter) const;
virtual bool Matches(const char* jobName,
const char* eventName);
private:
Event* fEvent;
};
class AbstractExternalEventLogItem : public LogItem {
public:
AbstractExternalEventLogItem(const char* name);
virtual ~AbstractExternalEventLogItem();
virtual status_t GetParameter(BMessage& parameter) const;
virtual bool Matches(const char* jobName,
const char* eventName);
protected:
BString fEventName;
};
class ExternalEventLogItem : public AbstractExternalEventLogItem {
public:
ExternalEventLogItem(const char* name);
virtual ~ExternalEventLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
};
class ExternalEventRegisteredLogItem : public AbstractExternalEventLogItem {
public:
ExternalEventRegisteredLogItem(
const char* name);
virtual ~ExternalEventRegisteredLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
};
class ExternalEventUnregisteredLogItem : public AbstractExternalEventLogItem {
public:
ExternalEventUnregisteredLogItem(
const char* name);
virtual ~ExternalEventUnregisteredLogItem();
virtual LogItemType Type() const;
virtual status_t GetMessage(BString& target) const;
};
// #pragma mark -
LogItem::LogItem()
:
fWhen(system_time())
{
}
LogItem::~LogItem()
{
}
BString
LogItem::Message() const
{
BString message;
GetMessage(message);
return message;
}
// #pragma mark - Log
Log::Log()
:
fCount(0)
{
mutex_init(&fLock, "log lock");
}
void
Log::Add(LogItem* item)
{
MutexLocker locker(fLock);
if (fCount == kMaxItems)
fItems.Remove(fItems.First());
else
fCount++;
fItems.Add(item);
}
void
Log::JobInitialized(Job* job)
{
LogItem* item = new(std::nothrow) JobInitializedLogItem(job);
if (item != NULL)
Add(item);
else
debug_printf("Initialized job \"%s\"\n", job->Name());
}
void
Log::JobIgnored(Job* job, status_t status)
{
LogItem* item = new(std::nothrow) JobIgnoredLogItem(job, status);
if (item != NULL)
Add(item);
else {
debug_printf("Ignored job \"%s\": %s\n", job->Name(),
strerror(status));
}
}
void
Log::JobLaunched(Job* job, status_t status)
{
LogItem* item = new(std::nothrow) JobLaunchedLogItem(job, status);
if (item != NULL)
Add(item);
else {
debug_printf("Launched job \"%s\": %s\n", job->Name(),
strerror(status));
}
}
void
Log::JobTerminated(Job* job, status_t status)
{
LogItem* item = new(std::nothrow) JobTerminatedLogItem(job, status);
if (item != NULL)
Add(item);
else {
debug_printf("Terminated job \"%s\": %s\n", job->Name(),
strerror(status));
}
}
void
Log::JobEnabled(Job* job, bool enabled)
{
LogItem* item = new(std::nothrow) JobEnabledLogItem(job, enabled);
if (item != NULL)
Add(item);
else
debug_printf("Enabled job \"%s\": %d\n", job->Name(), enabled);
}
void
Log::JobStopped(BaseJob* job, bool force)
{
LogItem* item = new(std::nothrow) JobStoppedLogItem(job, force);
if (item != NULL)
Add(item);
else
debug_printf("Stopped job \"%s\"\n", job->Name());
}
void
Log::EventTriggered(BaseJob* job, Event* event)
{
LogItem* item = new(std::nothrow) EventLogItem(job, event);
if (item != NULL)
Add(item);
else {
debug_printf("Event triggered for \"%s\": %s\n", job->Name(),
event->ToString().String());
}
}
void
Log::ExternalEventTriggered(const char* name)
{
LogItem* item = new(std::nothrow) ExternalEventLogItem(name);
if (item != NULL)
Add(item);
else
debug_printf("External event triggered: %s\n", name);
}
void
Log::ExternalEventRegistered(const char* name)
{
LogItem* item = new(std::nothrow) ExternalEventRegisteredLogItem(name);
if (item != NULL)
Add(item);
else
debug_printf("External event registered: %s\n", name);
}
void
Log::ExternalEventUnregistered(const char* name)
{
LogItem* item = new(std::nothrow) ExternalEventUnregisteredLogItem(name);
if (item != NULL)
Add(item);
else
debug_printf("External event unregistered: %s\n", name);
}
// #pragma mark - AbstractJobLogItem
AbstractJobLogItem::AbstractJobLogItem(BaseJob* job)
:
fJob(job)
{
}
AbstractJobLogItem::~AbstractJobLogItem()
{
}
status_t
AbstractJobLogItem::GetParameter(BMessage& parameter) const
{
return parameter.AddString("job", fJob->Name());
}
bool
AbstractJobLogItem::Matches(const char* jobName, const char* eventName)
{
if (jobName == NULL && eventName == NULL)
return true;
if (jobName != NULL && strcmp(fJob->Name(), jobName) == 0)
return true;
return false;
}
// #pragma mark - JobInitializedLogItem
JobInitializedLogItem::JobInitializedLogItem(Job* job)
:
AbstractJobLogItem(job)
{
}
JobInitializedLogItem::~JobInitializedLogItem()
{
}
LogItemType
JobInitializedLogItem::Type() const
{
return kJobInitialized;
}
status_t
JobInitializedLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Job \"%s\" initialized.", fJob->Name());
return B_OK;
}
// #pragma mark - JobIgnoredLogItem
JobIgnoredLogItem::JobIgnoredLogItem(Job* job, status_t error)
:
fJobName(job->Name()),
fError(error)
{
}
JobIgnoredLogItem::~JobIgnoredLogItem()
{
}
LogItemType
JobIgnoredLogItem::Type() const
{
return kJobIgnored;
}
status_t
JobIgnoredLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Ignored job \"%s\" due %s", fJobName.String(),
strerror(fError));
return B_OK;
}
status_t
JobIgnoredLogItem::GetParameter(BMessage& parameter) const
{
status_t status = parameter.AddString("job", fJobName);
if (status == B_OK)
status = parameter.AddInt32("error", fError);
return status;
}
bool
JobIgnoredLogItem::Matches(const char* jobName, const char* eventName)
{
if (jobName == NULL && eventName == NULL)
return true;
if (jobName != NULL && fJobName == jobName)
return true;
return false;
}
// #pragma mark - JobLaunchedLogItem
JobLaunchedLogItem::JobLaunchedLogItem(Job* job, status_t status)
:
AbstractJobLogItem(job),
fStatus(status)
{
}
JobLaunchedLogItem::~JobLaunchedLogItem()
{
}
LogItemType
JobLaunchedLogItem::Type() const
{
return kJobLaunched;
}
status_t
JobLaunchedLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Job \"%s\" launched: %s", fJob->Name(),
strerror(fStatus));
return B_OK;
}
status_t
JobLaunchedLogItem::GetParameter(BMessage& parameter) const
{
status_t status = AbstractJobLogItem::GetParameter(parameter);
if (status == B_OK)
status = parameter.AddInt32("status", fStatus);
return status;
}
// #pragma mark - JobTerminatedLogItem
JobTerminatedLogItem::JobTerminatedLogItem(Job* job, status_t status)
:
AbstractJobLogItem(job),
fStatus(status)
{
}
JobTerminatedLogItem::~JobTerminatedLogItem()
{
}
LogItemType
JobTerminatedLogItem::Type() const
{
return kJobTerminated;
}
status_t
JobTerminatedLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Job \"%s\" terminated: %s", fJob->Name(),
strerror(fStatus));
return B_OK;
}
status_t
JobTerminatedLogItem::GetParameter(BMessage& parameter) const
{
status_t status = AbstractJobLogItem::GetParameter(parameter);
if (status == B_OK)
status = parameter.AddInt32("status", fStatus);
return status;
}
// #pragma mark - JobEnabledLogItem
JobEnabledLogItem::JobEnabledLogItem(Job* job, bool enabled)
:
AbstractJobLogItem(job),
fEnabled(enabled)
{
}
JobEnabledLogItem::~JobEnabledLogItem()
{
}
LogItemType
JobEnabledLogItem::Type() const
{
return kJobEnabled;
}
status_t
JobEnabledLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Job \"%s\" %sabled", fJob->Name(),
fEnabled ? "en" : "dis");
return B_OK;
}
status_t
JobEnabledLogItem::GetParameter(BMessage& parameter) const
{
status_t status = AbstractJobLogItem::GetParameter(parameter);
if (status == B_OK)
status = parameter.AddBool("enabled", fEnabled);
return status;
}
// #pragma mark - JobStoppedLogItem
JobStoppedLogItem::JobStoppedLogItem(BaseJob* job, bool force)
:
AbstractJobLogItem(job),
fForce(force)
{
}
JobStoppedLogItem::~JobStoppedLogItem()
{
}
LogItemType
JobStoppedLogItem::Type() const
{
return kJobStopped;
}
status_t
JobStoppedLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Job \"%s\" %sstopped", fJob->Name(),
fForce ? "force " : "");
return B_OK;
}
status_t
JobStoppedLogItem::GetParameter(BMessage& parameter) const
{
status_t status = AbstractJobLogItem::GetParameter(parameter);
if (status == B_OK)
status = parameter.AddBool("force", fForce);
return status;
}
// #pragma mark - EventLogItem
EventLogItem::EventLogItem(BaseJob* job, Event* event)
:
AbstractJobLogItem(job),
fEvent(event)
{
}
EventLogItem::~EventLogItem()
{
}
LogItemType
EventLogItem::Type() const
{
return kEvent;
}
status_t
EventLogItem::GetMessage(BString& target) const
{
target.SetToFormat("Event triggered \"%s\": \"%s\"", fJob->Name(),
fEvent->ToString().String());
return B_OK;
}
status_t
EventLogItem::GetParameter(BMessage& parameter) const
{
status_t status = AbstractJobLogItem::GetParameter(parameter);
if (status == B_OK)
status = parameter.AddString("event", fEvent->ToString());
return status;
}
bool
EventLogItem::Matches(const char* jobName, const char* eventName)
{
if (eventName != NULL && strstr(fEvent->ToString(), eventName) == NULL)
return false;
return AbstractJobLogItem::Matches(jobName, NULL);
}
// #pragma mark - ExternalEventLogItem
AbstractExternalEventLogItem::AbstractExternalEventLogItem(const char* name)
:
fEventName(name)
{
}
AbstractExternalEventLogItem::~AbstractExternalEventLogItem()
{
}
status_t
AbstractExternalEventLogItem::GetParameter(BMessage& parameter) const
{
return parameter.AddString("event", fEventName);
}
bool
AbstractExternalEventLogItem::Matches(const char* jobName,
const char* eventName)
{
if (jobName == NULL && eventName == NULL)
return true;
if (eventName != NULL && strstr(fEventName.String(), eventName) != NULL)
return true;
return false;
}
// #pragma mark - ExternalEventLogItem
ExternalEventLogItem::ExternalEventLogItem(const char* name)
:
AbstractExternalEventLogItem(name)
{
}
ExternalEventLogItem::~ExternalEventLogItem()
{
}
LogItemType
ExternalEventLogItem::Type() const
{
return kExternalEvent;
}
status_t
ExternalEventLogItem::GetMessage(BString& target) const
{
target.SetToFormat("External event triggered: \"%s\"",
fEventName.String());
return B_OK;
}
// #pragma mark - ExternalEventRegisteredLogItem
ExternalEventRegisteredLogItem::ExternalEventRegisteredLogItem(const char* name)
:
AbstractExternalEventLogItem(name)
{
}
ExternalEventRegisteredLogItem::~ExternalEventRegisteredLogItem()
{
}
LogItemType
ExternalEventRegisteredLogItem::Type() const
{
return kExternalEventRegistered;
}
status_t
ExternalEventRegisteredLogItem::GetMessage(BString& target) const
{
target.SetToFormat("External event registered: \"%s\"",
fEventName.String());
return B_OK;
}
// #pragma mark - ExternalEventUnregisteredLogItem
ExternalEventUnregisteredLogItem::ExternalEventUnregisteredLogItem(
const char* name)
:
AbstractExternalEventLogItem(name)
{
}
ExternalEventUnregisteredLogItem::~ExternalEventUnregisteredLogItem()
{
}
LogItemType
ExternalEventUnregisteredLogItem::Type() const
{
return kExternalEventUnregistered;
}
status_t
ExternalEventUnregisteredLogItem::GetMessage(BString& target) const
{
target.SetToFormat("External event unregistered: \"%s\"",
fEventName.String());
return B_OK;
}

95
src/servers/launch/Log.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright 2017-2018, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#ifndef LOG_H
#define LOG_H
#include <String.h>
#include <locks.h>
#include <util/DoublyLinkedList.h>
class BMessage;
class BaseJob;
class Event;
class Job;
enum LogItemType {
kJobInitialized,
kJobIgnored,
kJobLaunched,
kJobTerminated,
kJobEnabled,
kJobStopped,
kEvent,
kExternalEvent,
kExternalEventRegistered,
kExternalEventUnregistered,
};
class LogItem : public DoublyLinkedListLinkImpl<LogItem> {
public:
public:
LogItem();
virtual ~LogItem();
bigtime_t When()
{ return fWhen; }
BString Message() const;
virtual LogItemType Type() const = 0;
virtual status_t GetMessage(BString& target) const = 0;
virtual status_t GetParameter(BMessage& parameter) const = 0;
virtual bool Matches(const char* jobName,
const char* eventName) = 0;
private:
bigtime_t fWhen;
};
typedef DoublyLinkedList<LogItem> LogItemList;
class Log {
public:
Log();
void Add(LogItem* item);
LogItemList::Iterator
Iterator()
{ return fItems.GetIterator(); }
mutex& Lock()
{ return fLock; }
void JobInitialized(Job* job);
void JobIgnored(Job* job, status_t status);
void JobLaunched(Job* job, status_t status);
void JobTerminated(Job* job, status_t status);
void JobEnabled(Job* job, bool enabled);
void JobStopped(BaseJob* job, bool force);
void EventTriggered(BaseJob* job, Event* event);
void ExternalEventTriggered(const char* name);
void ExternalEventRegistered(const char* name);
void ExternalEventUnregistered(const char* name);
private:
mutex fLock;
LogItemList fItems;
size_t fCount;
};
#endif // LOG_H

View File

@ -2,7 +2,7 @@ SubDir HAIKU_TOP src tests servers launch ;
AddSubDirSupportedPlatforms libbe_test ;
UsePrivateHeaders app libroot shared storage support ;
UsePrivateHeaders app kernel libroot shared storage support ;
UsePrivateSystemHeaders ;
UseHeaders [ FDirName $(HAIKU_TOP) src bin multiuser ] ;
@ -39,6 +39,7 @@ Server test_launch_daemon :
Conditions.cpp
Events.cpp
Job.cpp
Log.cpp
NetworkWatcher.cpp
SettingsParser.cpp
Target.cpp