blob: 8ebafc08dd2877e8cce28a6e0280e8ec5e49ae64 [file] [log] [blame]
#include <string.h>
#include "WPILib/Timer.h"
#include "WPILib/Task.h"
#include "aos/aos_core.h"
#include "aos/common/network/SendSocket.h"
#include "aos/common/Configuration.h"
#include "aos/common/die.h"
#undef ERROR
#define DECL_LEVEL(name, value) const log_level name = value;
DECL_LEVELS
#undef DECL_LEVEL
//#define fprintf(...)
namespace aos {
namespace logging {
namespace {
MSG_Q_ID queue;
uint8_t sequence = 0;
// This gets run in a low-priority task to take the logs from the queue and send
// them to the atom over a TCP socket.
void DoTask() {
SendSocket sock;
log_crio_message msg;
while (true) {
const int ret = msgQReceive(queue, reinterpret_cast<char *>(&msg),
sizeof(msg), WAIT_FOREVER);
if (ret == ERROR) {
fprintf(stderr, "logging: warning: receiving a message failed"
" with %d (%s)", errno, strerror(errno));
continue;
}
if (ret != sizeof(msg)) {
fprintf(stderr, "logging: warning: received a message of size %d "
"instead of %zd\n", ret, sizeof(msg));
continue;
}
if (sock.LastStatus() != 0) {
if (sock.Connect(NetworkPort::kLogs,
configuration::GetIPAddress(
configuration::NetworkDevice::kAtom),
SOCK_STREAM) != 0) {
fprintf(stderr, "logging: warning: connecting failed"
" because of %d: %s\n", errno, strerror(errno));
}
}
sock.Send(&msg, sizeof(msg));
if (sock.LastStatus() != 0) {
fprintf(stderr, "logging: warning: sending '%s' failed"
" because of %d: %s\n", msg.message, errno, strerror(errno));
}
}
}
} // namespace
void Start() {
queue = msgQCreate(100, // max messages
sizeof(log_crio_message),
MSG_Q_PRIORITY);
Task *task = new Task("LogSender",
(FUNCPTR)(DoTask),
150); // priority
task->Start();
}
int Do(log_level level, const char *format, ...) {
log_crio_message msg;
msg.time = Timer::GetFPGATimestamp();
msg.level = level;
msg.sequence = __sync_fetch_and_add(&sequence, 1);
const char *continued = "...";
const size_t size = sizeof(msg.message) - strlen(continued);
va_list ap;
va_start(ap, format);
const int ret = vsnprintf(msg.message, size, format, ap);
va_end(ap);
if (ret < 0) {
fprintf(stderr, "logging: error: vsnprintf failed with %d (%s)\n",
errno, strerror(errno));
return -1;
} else if (static_cast<uintmax_t>(ret) >= static_cast<uintmax_t>(size)) {
// overwrite the NULL at the end of the existing one and
// copy in the one on the end of continued
memcpy(&msg.message[size - 1], continued, strlen(continued) + 1);
}
if (msgQSend(queue, reinterpret_cast<char *>(&msg), sizeof(msg),
NO_WAIT, MSG_PRI_NORMAL) == ERROR) {
fprintf(stderr, "logging: warning: sending message '%s'"
" failed with %d (%s)", msg.message, errno, strerror(errno));
return -1;
}
if (level == FATAL) {
aos::Die("%s", msg.message);
}
return 0;
}
} // namespace logging
} // namespace aos