Implemented syslog output. For now, it will be put into /tmp (i.e. the tests
won't clobber your existing syslog). The time stamp is currently #ifdef'd out. We might think about adding some prefs; the facility could also only printed for kernel messages (like in Be's implementation). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5343 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
fe4817d5c0
commit
1cb317b43c
@ -6,13 +6,151 @@
|
|||||||
|
|
||||||
#include "syslog_output.h"
|
#include "syslog_output.h"
|
||||||
|
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Path.h>
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const size_t kMaxLogSize = 524288; // 512kB
|
||||||
|
|
||||||
|
static const char *kFacilities[] = {
|
||||||
|
"KERN", "USER", "MAIL", "DAEMON",
|
||||||
|
"AUTH", "SYSLOGD", "LPR", "NEWS",
|
||||||
|
"UUCP", "CRON", "AUTHPRIV",
|
||||||
|
"", "", "", "", "",
|
||||||
|
"LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3",
|
||||||
|
"LOCAL4", "LOCAL5", "LOCAL6", "LOCAL7",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const int32 kNumFacilities = 24;
|
||||||
|
|
||||||
|
int sLog = -1;
|
||||||
|
char sLastMessage[1024];
|
||||||
|
thread_id sLastThread;
|
||||||
|
int32 sRepeatCount;
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
prepare_output()
|
||||||
|
{
|
||||||
|
bool needNew = true;
|
||||||
|
bool tooLarge = false;
|
||||||
|
|
||||||
|
if (sLog > 0) {
|
||||||
|
// check file size
|
||||||
|
struct stat stat;
|
||||||
|
if (fstat(sLog, &stat) == 0) {
|
||||||
|
if (stat.st_size < kMaxLogSize)
|
||||||
|
needNew = false;
|
||||||
|
else
|
||||||
|
tooLarge = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needNew) {
|
||||||
|
// get path
|
||||||
|
BPath base;
|
||||||
|
find_directory(/*B_COMMON_LOG_DIRECTORY*/B_COMMON_TEMP_DIRECTORY, &base);
|
||||||
|
// ToDo: change to correct "which" parameter!
|
||||||
|
|
||||||
|
BPath syslog(base);
|
||||||
|
syslog.Append("syslog");
|
||||||
|
|
||||||
|
// move old file if it already exists
|
||||||
|
if (tooLarge) {
|
||||||
|
base.Append("syslog.old");
|
||||||
|
rename(syslog.Path(), base.Path());
|
||||||
|
|
||||||
|
// ToDo: remove old file if space on device is tight?
|
||||||
|
}
|
||||||
|
|
||||||
|
// open file
|
||||||
|
sLog = open(syslog.Path(), O_APPEND | O_CREAT | O_WRONLY, 644);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sLog >= 0 ? B_OK : B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
write_to_log(const char *buffer, int32 length)
|
||||||
|
{
|
||||||
|
if (sRepeatCount > 0) {
|
||||||
|
char repeat[64];
|
||||||
|
ssize_t size = snprintf(repeat, sizeof(repeat),
|
||||||
|
"Last message repeated %ld time%s\n", sRepeatCount,
|
||||||
|
sRepeatCount > 1 ? "s" : "");
|
||||||
|
sRepeatCount = 0;
|
||||||
|
if (write(sLog, repeat, strlen(repeat)) < size)
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(sLog, buffer, length) < length)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
syslog_output(syslog_message &message)
|
syslog_output(syslog_message &message)
|
||||||
{
|
{
|
||||||
printf("'%s'[%ld]: %s\n", message.ident, message.from, message.message);
|
// did we get this message already?
|
||||||
|
if (message.from == sLastThread
|
||||||
|
&& !strncmp(message.message, sLastMessage, sizeof(sLastMessage))) {
|
||||||
|
sRepeatCount++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[4096];
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// parse & nicely print the time stamp from the message
|
||||||
|
struct tm when;
|
||||||
|
localtime_r(&message.when, &when);
|
||||||
|
int32 pos = strftime(buffer, sizeof(buffer), "%b %d, %H:%M:%S ", &when);
|
||||||
|
#else
|
||||||
|
int32 pos = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add facility
|
||||||
|
int facility = SYSLOG_FACILITY_INDEX(message.priority);
|
||||||
|
if (facility >= kNumFacilities)
|
||||||
|
facility = SYSLOG_FACILITY_INDEX(LOG_USER);
|
||||||
|
pos += snprintf(buffer + pos, sizeof(buffer) - pos, "%s", kFacilities[facility]);
|
||||||
|
|
||||||
|
// add ident/thread ID
|
||||||
|
if (message.ident[0] == '\0') {
|
||||||
|
// ToDo: find out team name?
|
||||||
|
} else
|
||||||
|
pos += snprintf(buffer + pos, sizeof(buffer) - pos, " '%s'", message.ident);
|
||||||
|
|
||||||
|
if (message.options & LOG_PID)
|
||||||
|
pos += snprintf(buffer + pos, sizeof(buffer) - pos, "[%ld]", message.from);
|
||||||
|
|
||||||
|
// add message itself
|
||||||
|
int32 length = pos + snprintf(buffer + pos, sizeof(buffer) - pos, ": %s\n", message.message);
|
||||||
|
|
||||||
|
// ToDo: be less lazy about it - there is virtually no reason to truncate the message
|
||||||
|
if (strlen(message.message) > sizeof(buffer) - pos - 1)
|
||||||
|
strcpy(&buffer[sizeof(buffer) - 8], "<TRUNC>\n");
|
||||||
|
|
||||||
|
// dump message
|
||||||
|
|
||||||
|
if (prepare_output() < B_OK
|
||||||
|
|| write_to_log(buffer, length) < B_OK) {
|
||||||
|
// cannot write to syslog!
|
||||||
|
fputs(buffer, stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save this message to suppress repeated messages
|
||||||
|
strlcpy(sLastMessage, message.message, sizeof(sLastMessage));
|
||||||
|
sLastThread = message.from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user