mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
Logger implementation
This commit is contained in:
parent
1e2352bb30
commit
11267860f3
142
libuavcan/include/uavcan/protocol/logger.hpp
Normal file
142
libuavcan/include/uavcan/protocol/logger.hpp
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <uavcan/time.hpp>
|
||||
#include <uavcan/debug.hpp>
|
||||
#include <uavcan/protocol/debug/LogMessage.hpp>
|
||||
#include <uavcan/marshal/char_array_formatter.hpp>
|
||||
#include <uavcan/node/publisher.hpp>
|
||||
|
||||
#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
|
||||
# error UAVCAN_CPP_VERSION
|
||||
#endif
|
||||
|
||||
namespace uavcan
|
||||
{
|
||||
|
||||
class ILogSink
|
||||
{
|
||||
public:
|
||||
virtual ~ILogSink() { }
|
||||
virtual void log(const protocol::debug::LogMessage& message) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
typedef typename StorageType<typename protocol::debug::LogLevel::FieldTypes::value>::Type LogLevel;
|
||||
|
||||
static const LogLevel LevelAboveAll = (protocol::debug::LogLevel::FieldTypes::value::BitLen << 1) - 1;
|
||||
|
||||
private:
|
||||
enum { DefaultTxTimeoutMs = 2000 };
|
||||
|
||||
Publisher<protocol::debug::LogMessage> logmsg_pub_;
|
||||
protocol::debug::LogMessage msg_buf_;
|
||||
LogLevel level_;
|
||||
ILogSink* external_sink_;
|
||||
|
||||
public:
|
||||
Logger(INode& node)
|
||||
: logmsg_pub_(node)
|
||||
, external_sink_(NULL)
|
||||
{
|
||||
level_ = protocol::debug::LogLevel::ERROR;
|
||||
setTxTimeout(MonotonicDuration::fromMSec(DefaultTxTimeoutMs));
|
||||
assert(getTxTimeout() == MonotonicDuration::fromMSec(DefaultTxTimeoutMs));
|
||||
}
|
||||
|
||||
int log(const protocol::debug::LogMessage& message);
|
||||
|
||||
LogLevel getLevel() const { return level_; }
|
||||
void setLevel(LogLevel level) { level_ = level; }
|
||||
|
||||
ILogSink* getExternalSink() const { return external_sink_; }
|
||||
void setExternalSink(ILogSink* sink) { external_sink_ = sink; }
|
||||
|
||||
MonotonicDuration getTxTimeout() const { return logmsg_pub_.getTxTimeout(); }
|
||||
void setTxTimeout(MonotonicDuration val) { logmsg_pub_.setTxTimeout(val); }
|
||||
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
|
||||
template <typename... Args>
|
||||
int log(LogLevel level, const char* source, const char* format, Args... args)
|
||||
{
|
||||
if (level >= level_)
|
||||
{
|
||||
msg_buf_.level.value = level;
|
||||
msg_buf_.source = source;
|
||||
msg_buf_.text.clear();
|
||||
CharArrayFormatter<typename protocol::debug::LogMessage::FieldTypes::text> formatter(msg_buf_.text);
|
||||
formatter.write(format, args...);
|
||||
return log(msg_buf_);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
int logDebug(const char* source, const char* format, Args... args)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::DEBUG, source, format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
int logInfo(const char* source, const char* format, Args... args)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::INFO, source, format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
int logWarning(const char* source, const char* format, Args... args)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::WARNING, source, format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
int logError(const char* source, const char* format, Args... args)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::ERROR, source, format, args...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int log(LogLevel level, const char* source, const char* text)
|
||||
{
|
||||
if (level >= level_)
|
||||
{
|
||||
msg_buf_.level.value = level;
|
||||
msg_buf_.source = source;
|
||||
msg_buf_.text = text;
|
||||
return log(msg_buf_);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int logDebug(const char* source, const char* text)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::DEBUG, source, text);
|
||||
}
|
||||
|
||||
int logInfo(const char* source, const char* text)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::INFO, source, text);
|
||||
}
|
||||
|
||||
int logWarning(const char* source, const char* text)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::WARNING, source, text);
|
||||
}
|
||||
|
||||
int logError(const char* source, const char* text)
|
||||
{
|
||||
return log(protocol::debug::LogLevel::ERROR, source, text);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
26
libuavcan/src/protocol/logger.cpp
Normal file
26
libuavcan/src/protocol/logger.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <uavcan/protocol/logger.hpp>
|
||||
|
||||
namespace uavcan
|
||||
{
|
||||
|
||||
const Logger::LogLevel Logger::LevelAboveAll;
|
||||
|
||||
int Logger::log(const protocol::debug::LogMessage& message)
|
||||
{
|
||||
if (message.level.value >= level_)
|
||||
{
|
||||
const int res = logmsg_pub_.broadcast(message);
|
||||
if (external_sink_)
|
||||
{
|
||||
external_sink_->log(message);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
123
libuavcan/test/protocol/logger.cpp
Normal file
123
libuavcan/test/protocol/logger.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/protocol/logger.hpp>
|
||||
#include "helpers.hpp"
|
||||
|
||||
|
||||
struct LogSink : public uavcan::ILogSink
|
||||
{
|
||||
std::queue<uavcan::protocol::debug::LogMessage> msgs;
|
||||
|
||||
void log(const uavcan::protocol::debug::LogMessage& message)
|
||||
{
|
||||
msgs.push(message);
|
||||
std::cout << message << std::endl;
|
||||
}
|
||||
|
||||
uavcan::protocol::debug::LogMessage pop()
|
||||
{
|
||||
if (msgs.empty())
|
||||
{
|
||||
std::cout << "LogSink is empty" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
const uavcan::protocol::debug::LogMessage m = msgs.front();
|
||||
msgs.pop();
|
||||
return m;
|
||||
}
|
||||
|
||||
bool popMatchByLevelAndText(int level, const std::string& source, const std::string& text)
|
||||
{
|
||||
const uavcan::protocol::debug::LogMessage m = pop();
|
||||
return
|
||||
level == m.level.value &&
|
||||
source == m.source &&
|
||||
text == m.text;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(Logger, Basic)
|
||||
{
|
||||
InterlinkedTestNodes nodes;
|
||||
|
||||
uavcan::Logger logger(nodes.a);
|
||||
|
||||
ASSERT_EQ(uavcan::protocol::debug::LogLevel::ERROR, logger.getLevel());
|
||||
|
||||
LogSink sink;
|
||||
|
||||
// Will fail - types are not registered
|
||||
uavcan::GlobalDataTypeRegistry::instance().reset();
|
||||
ASSERT_GT(0, logger.logError("foo", "Error (fail - type is not registered)"));
|
||||
ASSERT_EQ(0, logger.logDebug("foo", "Debug (ignored - low logging level)"));
|
||||
|
||||
ASSERT_FALSE(logger.getExternalSink());
|
||||
logger.setExternalSink(&sink);
|
||||
ASSERT_EQ(&sink, logger.getExternalSink());
|
||||
|
||||
uavcan::GlobalDataTypeRegistry::instance().reset();
|
||||
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::debug::LogMessage> _reg1;
|
||||
|
||||
SubscriberWithCollector<uavcan::protocol::debug::LogMessage> log_sub(nodes.b);
|
||||
ASSERT_LE(0, log_sub.start());
|
||||
|
||||
ASSERT_EQ(0, logger.logDebug("foo", "Debug (ignored due to low logging level)"));
|
||||
ASSERT_LE(0, logger.logError("foo", "Error"));
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2));
|
||||
ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::ERROR);
|
||||
ASSERT_EQ(log_sub.collector.msg->source, "foo");
|
||||
ASSERT_EQ(log_sub.collector.msg->text, "Error");
|
||||
|
||||
logger.setLevel(uavcan::protocol::debug::LogLevel::DEBUG);
|
||||
ASSERT_LE(0, logger.logWarning("foo", "Warning"));
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2));
|
||||
ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::WARNING);
|
||||
ASSERT_EQ(log_sub.collector.msg->source, "foo");
|
||||
ASSERT_EQ(log_sub.collector.msg->text, "Warning");
|
||||
|
||||
ASSERT_LE(0, logger.logInfo("foo", "Info"));
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2));
|
||||
ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::INFO);
|
||||
ASSERT_EQ(log_sub.collector.msg->source, "foo");
|
||||
ASSERT_EQ(log_sub.collector.msg->text, "Info");
|
||||
|
||||
ASSERT_LE(0, logger.logDebug("foo", "Debug"));
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2));
|
||||
ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::DEBUG);
|
||||
ASSERT_EQ(log_sub.collector.msg->source, "foo");
|
||||
ASSERT_EQ(log_sub.collector.msg->text, "Debug");
|
||||
|
||||
ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::ERROR, "foo", "Error"));
|
||||
ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::WARNING, "foo", "Warning"));
|
||||
ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::INFO, "foo", "Info"));
|
||||
ASSERT_TRUE(sink.popMatchByLevelAndText(uavcan::protocol::debug::LogLevel::DEBUG, "foo", "Debug"));
|
||||
}
|
||||
|
||||
#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
|
||||
# error UAVCAN_CPP_VERSION
|
||||
#endif
|
||||
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
|
||||
TEST(Logger, Cpp11Formatting)
|
||||
{
|
||||
InterlinkedTestNodes nodes;
|
||||
|
||||
uavcan::Logger logger(nodes.a);
|
||||
logger.setLevel(uavcan::protocol::debug::LogLevel::DEBUG);
|
||||
|
||||
SubscriberWithCollector<uavcan::protocol::debug::LogMessage> log_sub(nodes.b);
|
||||
ASSERT_LE(0, log_sub.start());
|
||||
|
||||
ASSERT_LE(0, logger.logWarning("foo", "char='%*', %* is %*", '$', "double", 12.34));
|
||||
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(2));
|
||||
ASSERT_EQ(log_sub.collector.msg->level.value, uavcan::protocol::debug::LogLevel::WARNING);
|
||||
ASSERT_EQ(log_sub.collector.msg->source, "foo");
|
||||
ASSERT_EQ(log_sub.collector.msg->text, "char='$', double is 12.340000");
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user