got binary logging actually fully working (!!!)
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index bdc14ec..0413072 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -57,16 +57,15 @@
} // namespace
namespace internal {
+namespace {
-void FillInMessage(log_level level, const char *format, va_list ap,
- LogMessage *message) {
+void FillInMessageBase(log_level level, LogMessage *message) {
Context *context = Context::Get();
- ExecuteFormat(message->message, sizeof(message->message), format, ap);
-
message->level = level;
message->source = context->source;
- memcpy(message->name, context->name.c_str(), context->name.size() + 1);
+ memcpy(message->name, context->name.c_str(), context->name.size());
+ message->name_length = context->name.size();
time::Time now = time::Time::Now();
message->seconds = now.sec();
@@ -75,12 +74,75 @@
message->sequence = context->sequence++;
}
+} // namespace
+
+void FillInMessageStructure(log_level level,
+ const ::std::string &message_string, size_t size,
+ const MessageType *type,
+ const ::std::function<size_t(char *)> &serialize,
+ LogMessage *message) {
+ type_cache::AddShm(type->id);
+ message->structure.type_id = type->id;
+
+ FillInMessageBase(level, message);
+
+ if (message_string.size() + size > sizeof(message->structure.serialized)) {
+ LOG(FATAL, "serialized struct %s (size %zd) and message %s too big\n",
+ type->name.c_str(), size, message_string.c_str());
+ }
+ message->structure.string_length = message_string.size();
+ memcpy(message->structure.serialized, message_string.data(),
+ message->structure.string_length);
+
+ message->message_length = serialize(
+ &message->structure.serialized[message->structure.string_length]);
+ message->type = LogMessage::Type::kStruct;
+}
+
+void FillInMessage(log_level level, const char *format, va_list ap,
+ LogMessage *message) {
+ FillInMessageBase(level, message);
+
+ message->message_length =
+ ExecuteFormat(message->message, sizeof(message->message), format, ap);
+ message->type = LogMessage::Type::kString;
+}
+
void PrintMessage(FILE *output, const LogMessage &message) {
- fprintf(output, "%s(%" PRId32 ")(%05" PRIu16 "): %s at"
- " %010" PRId32 ".%09" PRId32 "s: %s",
- message.name, static_cast<int32_t>(message.source), message.sequence,
- log_str(message.level), message.seconds, message.nseconds,
- message.message);
+#define BASE_FORMAT \
+ "%.*s(%" PRId32 ")(%05" PRIu16 "): %s at %010" PRId32 ".%09" PRId32 "s: "
+#define BASE_ARGS \
+ static_cast<int>(message.name_length), message.name, \
+ static_cast<int32_t>(message.source), message.sequence, \
+ log_str(message.level), message.seconds, message.nseconds
+ switch (message.type) {
+ case LogMessage::Type::kString:
+ fprintf(output, BASE_FORMAT "%.*s", BASE_ARGS,
+ static_cast<int>(message.message_length), message.message);
+ break;
+ case LogMessage::Type::kStruct:
+ char buffer[LOG_MESSAGE_LEN];
+ size_t output_length = sizeof(buffer);
+ size_t input_length = message.message_length;
+ if (!PrintMessage(
+ buffer, &output_length,
+ message.structure.serialized + message.structure.string_length,
+ &input_length, type_cache::Get(message.structure.type_id))) {
+ LOG(FATAL,
+ "printing message (%.*s) of type %s into %zu-byte buffer failed\n",
+ static_cast<int>(message.message_length), message.message,
+ type_cache::Get(message.structure.type_id).name.c_str(),
+ sizeof(buffer));
+ }
+ if (input_length > 0) {
+ LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
+ type_cache::Get(message.structure.type_id).name.c_str());
+ }
+ fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+ static_cast<int>(message.message_length), message.message,
+ static_cast<int>(output_length), buffer);
+ break;
+ }
}
} // namespace internal
diff --git a/aos/common/logging/logging_impl.h b/aos/common/logging/logging_impl.h
index f2d9752..3d5b387 100644
--- a/aos/common/logging/logging_impl.h
+++ b/aos/common/logging/logging_impl.h
@@ -40,21 +40,30 @@
// using a gcc function attribute.
// The struct that the code uses for making logging calls.
-// Packed so that it ends up the same under both linux and vxworks.
-struct __attribute__((packed)) LogMessage {
-#ifdef __VXWORKS__
- static_assert(sizeof(pid_t) == sizeof(int),
- "we use task IDs (aka ints) and pid_t interchangeably");
-#endif
- // Actually the task ID (aka a pointer to the TCB) on the cRIO.
+struct LogMessage {
+ enum class Type : uint8_t {
+ kString, kStruct,
+ };
+
+ int32_t seconds, nseconds;
+ // message_length is the length of everything in message for all types.
+ size_t message_length, name_length;
pid_t source;
static_assert(sizeof(source) == 4, "that's how they get printed");
// Per task/thread.
uint16_t sequence;
+ Type type;
log_level level;
- int32_t seconds, nseconds;
char name[100];
- char message[LOG_MESSAGE_LEN];
+ union {
+ char message[LOG_MESSAGE_LEN];
+ struct {
+ uint32_t type_id;
+ size_t string_length;
+ // The message string and then the serialized structure.
+ char serialized[LOG_MESSAGE_LEN - sizeof(type) - sizeof(string_length)];
+ } structure;
+ };
};
static_assert(shm_ok<LogMessage>::value, "it's going in a queue");
@@ -245,8 +254,16 @@
} cork_data;
};
-// Fills in *message according to the given inputs. Used for implementing
-// LogImplementation::DoLog.
+// Fills in all the parts of message according to the given inputs (with type
+// kStruct).
+void FillInMessageStructure(log_level level,
+ const ::std::string &message_string, size_t size,
+ const MessageType *type,
+ const ::std::function<size_t(char *)> &serialize,
+ LogMessage *message);
+
+// Fills in *message according to the given inputs (with type kString).
+// Used for implementing LogImplementation::DoLog.
void FillInMessage(log_level level, const char *format, va_list ap,
LogMessage *message);
@@ -255,8 +272,8 @@
// Prints format (with ap) into output and correctly deals with the result
// being too long etc.
-void ExecuteFormat(char *output, size_t output_size, const char *format,
- va_list ap);
+size_t ExecuteFormat(char *output, size_t output_size, const char *format,
+ va_list ap);
// Runs the given function with the current LogImplementation (handles switching
// it out while running function etc).
diff --git a/aos/common/logging/logging_interface.cc b/aos/common/logging/logging_interface.cc
index 68a88a8..b4244fb 100644
--- a/aos/common/logging/logging_interface.cc
+++ b/aos/common/logging/logging_interface.cc
@@ -4,6 +4,8 @@
#include <stdarg.h>
#include <string.h>
+#include <type_traits>
+
#include "aos/common/die.h"
// This file only contains the code necessary to link (ie no implementations).
@@ -21,19 +23,21 @@
cork_data.Reset();
}
-void ExecuteFormat(char *output, size_t output_size,
- const char *format, va_list ap) {
- static const char *continued = "...\n";
+size_t ExecuteFormat(char *output, size_t output_size, const char *format,
+ va_list ap) {
+ static const char *const continued = "...\n";
const size_t size = output_size - strlen(continued);
const int ret = vsnprintf(output, size, format, ap);
+ typedef ::std::common_type<typeof(ret), typeof(size)>::type RetType;
if (ret < 0) {
LOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed with %d (%s)\n",
output, size, format, errno, strerror(errno));
- } else if (static_cast<uintmax_t>(ret) >= static_cast<uintmax_t>(size)) {
+ } else if (static_cast<RetType>(ret) >= static_cast<RetType>(size)) {
// Overwrite the '\0' at the end of the existing data and
// copy in the one on the end of continued.
memcpy(&output[size - 1], continued, strlen(continued) + 1);
}
+ return ::std::min<RetType>(ret, size);
}
void RunWithCurrentImplementation(
diff --git a/aos/common/logging/queue_logging.h b/aos/common/logging/queue_logging.h
index 191d4c7..df343df 100644
--- a/aos/common/logging/queue_logging.h
+++ b/aos/common/logging/queue_logging.h
@@ -11,6 +11,7 @@
namespace aos {
namespace logging {
+#if 1
#define LOG_STRUCT(level, message, structure) \
do { \
static const ::std::string kAosLoggingMessage( \
@@ -23,6 +24,9 @@
abort(); \
} \
} while (false)
+#else
+#define LOG_STRUCT(level, message, structure)
+#endif
template <class T>
void DoLogStruct(log_level level, const ::std::string &message,