⛏️ index : haiku.git

/*
 * 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 JobSkippedLogItem : public LogItem {
public:
								JobSkippedLogItem(Job* job);
	virtual						~JobSkippedLogItem();

	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;
};


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::JobSkipped(Job* job)
{
	LogItem* item = new(std::nothrow) JobSkippedLogItem(job);
	if (item != NULL)
		Add(item);
	else {
		debug_printf("Skipped job \"%s\"\n", job->Name());
	}
}


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 - JobSkippedLogItem


JobSkippedLogItem::JobSkippedLogItem(Job* job)
	:
	fJobName(job->Name())
{
}


JobSkippedLogItem::~JobSkippedLogItem()
{
}


LogItemType
JobSkippedLogItem::Type() const
{
	return kJobSkipped;
}


status_t
JobSkippedLogItem::GetMessage(BString& target) const
{
	target.SetToFormat("Skipped job \"%s\"", fJobName.String());
	return B_OK;
}


status_t
JobSkippedLogItem::GetParameter(BMessage& parameter) const
{
	return parameter.AddString("job", fJobName);
}


bool
JobSkippedLogItem::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;
}