Output stream like operator << for Error (#4670)

To create an error human readable message should be provided among other argmunts.
Which is good to better understanding what happend by log records.
To make it more informative user in most cases should put in those message some data (numbers, strings etc.).
This operator will help us to avoid using verbose constructions like boost::format or std::ostringstream or something similar to format a proper error message.
We will be able just to "stream" in a created error any "printable" variables from the context.

Additionaly we will be able to use "fancy" tools for streams like boost::io::quoted or std::hex to format messages.

Example:
```c++
createError(SystemErorr::NoSuchFile, "Could not read pidfile: ")
  << boost::io::quoted(pidfile_path)
  << " " << read_status.toString();
```
This commit is contained in:
Alexander 2018-07-05 16:12:18 +01:00 committed by GitHub
parent b75821658b
commit 5fa1ebad13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 0 deletions

View File

@ -13,6 +13,7 @@
#include <boost/core/demangle.hpp>
#include <memory>
#include <new>
#include <sstream>
#include <string>
#include <typeinfo>
@ -97,6 +98,10 @@ class Error final : public ErrorBase {
return full_message;
}
void appendToMessage(const std::string& text) {
message_.append(text);
}
private:
ErrorCodeEnumType errorCode_;
std::string message_;
@ -160,4 +165,15 @@ Error<ErrorCodeEnumType> createError(
std::move(underlying_error)));
}
template <typename ErrorType,
typename ValueType,
typename = typename std::enable_if<
std::is_base_of<ErrorBase, ErrorType>::value>::type>
inline ErrorType operator<<(ErrorType&& error, const ValueType& value) {
std::ostringstream ostr{};
ostr << value;
error.appendToMessage(ostr.str());
return std::forward<ErrorType>(error);
}
} // namespace osquery

View File

@ -11,12 +11,14 @@
#include <gtest/gtest.h>
#include <boost/algorithm/string.hpp>
#include <boost/io/detail/quoted_manip.hpp>
#include <osquery/error.h>
enum class TestError {
SomeError = 1,
AnotherError = 2,
MusicError,
};
GTEST_TEST(ErrorTest, initialization) {
@ -85,3 +87,18 @@ GTEST_TEST(ErrorTest, createErrorFromOtherError) {
EXPECT_PRED2(stringContains, secondShortMsg, firstMsg);
EXPECT_PRED2(stringContains, secondShortMsg, secondMsg);
}
GTEST_TEST(ErrorTest, createErrorAndStreamToIt) {
const auto a4 = std::string{"A4"};
const auto err = osquery::createError(TestError::MusicError, "Do")
<< '-' << "Re"
<< "-Mi"
<< "-Fa"
<< "-Sol"
<< "-La"
<< "-Si La" << boost::io::quoted(a4) << ' ' << 440 << " Hz";
EXPECT_EQ(TestError::MusicError, err.getErrorCode());
auto fullMsg = err.getFullMessageRecursive();
EXPECT_PRED2(
stringContains, fullMsg, "Do-Re-Mi-Fa-Sol-La-Si La\"A4\" 440 Hz");
}