mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-12 10:23:50 +01:00
Even faster. Using internal MoveOnCopy struct-wrapper.
This commit is contained in:
parent
889145453d
commit
c28593e87e
@ -27,6 +27,7 @@ namespace g2 {
|
||||
}
|
||||
|
||||
LogMessageBuilder::~LogMessageBuilder() {
|
||||
_message.get()->write().append(stream().str());
|
||||
if (_message.get()->wasFatal()) {
|
||||
FatalMessageBuilder trigger(_message, SIGABRT);
|
||||
return; // FatalMessageBuilder will send to worker at scope exit
|
||||
@ -41,7 +42,7 @@ namespace g2 {
|
||||
}
|
||||
|
||||
std::ostringstream& LogMessageBuilder::stream() {
|
||||
return _message.get()->stream();
|
||||
return _stream;
|
||||
}
|
||||
|
||||
void LogMessageBuilder::messageSave(const char *printf_like_message, ...) {
|
||||
@ -72,7 +73,6 @@ namespace g2 {
|
||||
|
||||
|
||||
FatalMessageBuilder:: FatalMessageBuilder(LogMessagePtr details, int signal_id)
|
||||
//: _fatal_message(details), _fatal_signal(signal_id)
|
||||
: _fatal_message(std2::make_unique<FatalMessage>(*(details._move_only.get()), signal_id))
|
||||
{}
|
||||
|
||||
|
@ -44,5 +44,6 @@ namespace g2 {
|
||||
|
||||
private:
|
||||
LogMessagePtr _message;
|
||||
std::ostringstream _stream;
|
||||
};
|
||||
} // g2
|
@ -42,9 +42,9 @@ FileSink::~FileSink() {
|
||||
exit_msg.append({"\nLog file at: ["}).append(_log_file_with_path).append({"]\n\n"});
|
||||
std::cerr << exit_msg << std::flush;
|
||||
}
|
||||
void FileSink::fileWrite(std::shared_ptr<LogMessage> message) {
|
||||
void FileSink::fileWrite(LogMessageMover message) {
|
||||
std::ofstream& out(filestream());
|
||||
out << message->toString() << std::flush;
|
||||
out << message.get().toString() << std::flush;
|
||||
}
|
||||
|
||||
std::string FileSink::changeLogFile(const std::string& directory) {
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
FileSink(const std::string& log_prefix, const std::string& log_directory);
|
||||
virtual ~FileSink();
|
||||
|
||||
void fileWrite(std::shared_ptr<LogMessage> message);
|
||||
void fileWrite(LogMessageMover message);
|
||||
std::string changeLogFile(const std::string& directory);
|
||||
std::string fileName();
|
||||
|
||||
|
@ -100,9 +100,10 @@ namespace g2 {
|
||||
g_first_unintialized_msg = incoming.release();
|
||||
std::string err = {"LOGGER NOT INITIALIZED:\n\t\t"};
|
||||
err.append(g_first_unintialized_msg->message());
|
||||
auto& stream = g_first_unintialized_msg->stream();
|
||||
stream.str(err);
|
||||
std::cerr << stream.str() << std::endl;
|
||||
std::string& str = g_first_unintialized_msg->write();
|
||||
str.clear();
|
||||
str.append(err);
|
||||
std::cerr << str << std::endl;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ namespace g2 {
|
||||
|
||||
|
||||
|
||||
std::string LogMessage::toString() const {
|
||||
std::string LogMessage::toString() {
|
||||
std::string out;
|
||||
out.append("\n").append(timestamp()).append(".")
|
||||
.append(microseconds()).append("\t")
|
||||
@ -121,12 +121,12 @@ namespace g2 {
|
||||
: _timestamp(g2::systemtime_now())
|
||||
, _microseconds(microsecondsCounter())
|
||||
, _file(splitFileName(file)), _line(line), _function(function), _level(level)
|
||||
, _stream(std2::make_unique<std::ostringstream>()){}
|
||||
{}
|
||||
|
||||
|
||||
LogMessage::LogMessage(const std::string& fatalOsSignalCrashMessage)
|
||||
: LogMessage({""}, 0, {""}, internal::FATAL_SIGNAL) {
|
||||
stream() << fatalOsSignalCrashMessage;
|
||||
_message.append(fatalOsSignalCrashMessage);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const LogMessage& other)
|
||||
@ -137,8 +137,8 @@ namespace g2 {
|
||||
, _function(other._function)
|
||||
, _level(other._level)
|
||||
, _expression(other._expression)
|
||||
, _message(other._message)
|
||||
{
|
||||
stream().str(other.stream().str());
|
||||
}
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ namespace g2 {
|
||||
, _function(std::move(other._function))
|
||||
, _level(other._level)
|
||||
, _expression(std::move(other._expression))
|
||||
, _stream(std::move(other._stream)) {
|
||||
, _message(std::move(other._message)) {
|
||||
}
|
||||
|
||||
|
||||
@ -176,10 +176,11 @@ namespace g2 {
|
||||
// _level = other._level;
|
||||
// _expression = std::move(other._expression);
|
||||
// std::move(_stream, other._stream);
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
FatalMessage::FatalMessage(const LogMessage& details, int signal_id)
|
||||
|
@ -30,16 +30,17 @@ namespace g2 {
|
||||
|
||||
std::string timestamp(const std::string& time_format = {internal::date_formatted + " " + internal::time_formatted}) const;
|
||||
std::string microseconds() const { return std::to_string(_microseconds); }
|
||||
std::string message() const { return stream().str(); }
|
||||
std::string expression() const { return _expression; }
|
||||
bool wasFatal() const { return internal::wasFatal(_level); }
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
|
||||
std::ostringstream& stream() const { return *(_stream.get()); }
|
||||
std::string message() const { return _message; }
|
||||
std::string& write() const { return _message; }
|
||||
|
||||
std::string expression() { return _expression; }
|
||||
bool wasFatal() { return internal::wasFatal(_level); }
|
||||
|
||||
std::string toString();
|
||||
void setExpression(const std::string expression) { _expression = expression; }
|
||||
|
||||
|
||||
LogMessage(const std::string &file, const int line, const std::string& function, const LEVELS& level);
|
||||
explicit LogMessage(const std::string& fatalOsSignalCrashMessage);
|
||||
|
||||
@ -60,7 +61,8 @@ namespace g2 {
|
||||
std::string _function;
|
||||
LEVELS _level;
|
||||
std::string _expression; // only with content for CHECK(...) calls
|
||||
std::unique_ptr<std::ostringstream> _stream;
|
||||
//std::unique_ptr<std::ostringstream> _stream;
|
||||
mutable std::string _message;
|
||||
};
|
||||
|
||||
|
||||
@ -83,4 +85,5 @@ namespace g2 {
|
||||
|
||||
typedef MoveOnCopy<std::unique_ptr<FatalMessage>> FatalMessagePtr;
|
||||
typedef MoveOnCopy<std::unique_ptr<LogMessage>> LogMessagePtr;
|
||||
typedef MoveOnCopy<LogMessage> LogMessageMover;
|
||||
} // g2
|
||||
|
@ -34,38 +34,38 @@ struct LogWorkerImpl {
|
||||
_bg.reset();
|
||||
}
|
||||
|
||||
void bgSave(g2::LogMessagePtr msgPtr) {
|
||||
std::shared_ptr<LogMessage> msg(msgPtr.get().release());
|
||||
if (msg == nullptr) {
|
||||
std::cerr << "ERROR NULLPTR" << std::endl;
|
||||
return;
|
||||
|
||||
}
|
||||
void bgSave(g2::LogMessagePtr msgPtr) {
|
||||
std::unique_ptr<LogMessage> uniqueMsg(std::move(msgPtr.get()));
|
||||
|
||||
for (auto& sink : _sinks) {
|
||||
sink->send(msg);
|
||||
LogMessage msg(*(uniqueMsg));
|
||||
sink->send(LogMessageMover(std::move(msg)));
|
||||
}
|
||||
|
||||
if (_sinks.empty()) {
|
||||
std::string err_msg{"g2logworker has no sinks. Message: ["};
|
||||
err_msg.append(msg->toString()).append({"]\n"});
|
||||
err_msg.append(uniqueMsg.get()->toString()).append({"]\n"});
|
||||
std::cerr << err_msg;
|
||||
}
|
||||
}
|
||||
|
||||
void bgFatal(FatalMessagePtr msgPtr) {
|
||||
std::string signal = msgPtr.get()->signal();
|
||||
std::shared_ptr<LogMessage> message(msgPtr.release()); // = msgPtr.get()->copyToLogMessage();
|
||||
message->stream() << "\nExiting after fatal event (" << message->level()
|
||||
<< "). Exiting with signal: " << signal
|
||||
<< "\nLog content flushed flushed sucessfully to sink\n\n";
|
||||
auto fatal_signal_id = msgPtr.get()->_signal_id;
|
||||
|
||||
std::unique_ptr<LogMessage> uniqueMsg(std::move(msgPtr.get()));
|
||||
uniqueMsg->write().append("\nExiting after fatal event (").append(uniqueMsg->level());
|
||||
uniqueMsg->write().append("). Exiting with signal: ").append(signal)
|
||||
.append("\nLog content flushed flushed sucessfully to sink\n\n");
|
||||
|
||||
std::cerr << message->message() << std::flush;
|
||||
std::cerr << uniqueMsg->message() << std::flush;
|
||||
for (auto& sink : _sinks) {
|
||||
sink->send(message);
|
||||
LogMessage msg(*(uniqueMsg));
|
||||
sink->send(LogMessageMover(std::move(msg)));
|
||||
}
|
||||
_sinks.clear(); // flush all queues
|
||||
|
||||
internal::exitWithDefaultSignalHandler(msgPtr.get()->_signal_id);
|
||||
internal::exitWithDefaultSignalHandler(fatal_signal_id);
|
||||
// should never reach this point
|
||||
perror("g2log exited after receiving FATAL trigger. Flush message status: ");
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
namespace g2 {
|
||||
namespace internal {
|
||||
typedef std::function<void(std::shared_ptr<LogMessage>) > AsyncMessageCall;
|
||||
typedef std::function<void(LogMessageMover) > AsyncMessageCall;
|
||||
|
||||
/// The asynchronous Sink has an active object, incoming requests for actions
|
||||
// will be processed in the background by the specific object the Sink represents.
|
||||
@ -51,14 +51,14 @@ struct Sink : public SinkWrapper {
|
||||
_real_sink {sink},
|
||||
_bg(kjellkod::Active::createActive()) {
|
||||
auto adapter = std::bind(Call, _real_sink.get(), std::placeholders::_1);
|
||||
_default_log_call = [ = ](std::shared_ptr<LogMessage> m){adapter(m->toString());};
|
||||
_default_log_call = [ = ](LogMessageMover m){adapter(m.get().toString());};
|
||||
}
|
||||
|
||||
virtual ~Sink() {
|
||||
_bg.reset(); // TODO: to remove
|
||||
}
|
||||
|
||||
void send(std::shared_ptr<LogMessage> msg) override {
|
||||
void send(LogMessageMover msg) override {
|
||||
_bg->send([this, msg] {
|
||||
_default_log_call(msg);
|
||||
});
|
||||
|
@ -15,7 +15,7 @@ namespace g2 {
|
||||
|
||||
struct SinkWrapper {
|
||||
virtual ~SinkWrapper() { }
|
||||
virtual void send(std::shared_ptr<LogMessage> msg) = 0;
|
||||
virtual void send(LogMessageMover msg) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,265 +1,259 @@
|
||||
//#include <gtest/gtest.h>
|
||||
//
|
||||
//#include <memory>
|
||||
//#include <string>
|
||||
//#include <vector>
|
||||
//#include <thread>
|
||||
//#include <chrono>
|
||||
//#include <atomic>
|
||||
//
|
||||
//#include "testing_helpers.h"
|
||||
//#include "std2_make_unique.hpp"
|
||||
//#include "g2sink.h"
|
||||
//#include "g2sinkwrapper.h"
|
||||
//#include "g2sinkhandle.h"
|
||||
//#include "g2logmessage.hpp"
|
||||
//
|
||||
//
|
||||
//using namespace std;
|
||||
//using namespace std2;
|
||||
//using namespace testing_helpers;
|
||||
//
|
||||
//class CoutSink {
|
||||
// stringstream buffer;
|
||||
// unique_ptr<ScopedOut> scope_ptr;
|
||||
//
|
||||
// CoutSink() : scope_ptr(std2::make_unique<ScopedOut>(std::cout, &buffer)) { }
|
||||
//public:
|
||||
//
|
||||
// void clear() { buffer.str(""); }
|
||||
// std::string string() { return buffer.str(); }
|
||||
// void save(g2::LogMessage msg) {std::cout << msg.message();}
|
||||
// virtual ~CoutSink() final { }
|
||||
//
|
||||
// static std::unique_ptr<CoutSink> createSink() {
|
||||
// return std::unique_ptr<CoutSink>(new CoutSink);
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//
|
||||
//namespace {
|
||||
// typedef std::shared_ptr<g2::internal::SinkWrapper> SinkWrapperPtr;
|
||||
// typedef std::string LogEntry;
|
||||
//}
|
||||
//
|
||||
//namespace g2 {
|
||||
//
|
||||
// class Worker {
|
||||
// std::vector<SinkWrapperPtr> _container; // should be hidden in a pimple with a bg active object
|
||||
// std::unique_ptr<kjellkod::Active> _bg;
|
||||
//
|
||||
// void bgSave(LogEntry msg) {
|
||||
//// for (auto& sink : _container) {
|
||||
//// g2::LogMessage message("test", 0, "test", DEBUG);
|
||||
//// message.stream() << msg;
|
||||
//// sink->send(message);
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// public:
|
||||
//
|
||||
// Worker() : _bg { kjellkod::Active::createActive() }
|
||||
// {}
|
||||
//
|
||||
// ~Worker() {
|
||||
// _bg->send([this] { _container.clear(); });
|
||||
// }
|
||||
//
|
||||
// void save(LogEntry msg) {
|
||||
// _bg->send([this, msg] {
|
||||
// bgSave(msg); });
|
||||
// } // will this be copied?
|
||||
// //this is guaranteed to work std::bind(&Worker::bgSave, this, msg)); }
|
||||
//
|
||||
// template<typename T, typename DefaultLogCall>
|
||||
// std::unique_ptr< SinkHandle<T> > addSink(std::unique_ptr<T> unique, DefaultLogCall call) {
|
||||
//// auto shared = std::shared_ptr<T>(unique.release());
|
||||
//// auto sink = std::make_shared < internal::Sink<T> > (shared, call);
|
||||
//// auto add_sink_call = [this, sink] {
|
||||
//// _container.push_back(sink);
|
||||
//
|
||||
// }
|
||||
//// auto wait_result = g2::spawn_task(add_sink_call, _bg.get());
|
||||
//// wait_result.wait();
|
||||
//
|
||||
// auto handle = std2::make_unique< SinkHandle<T> >(sink);
|
||||
// return handle;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
//} // g2
|
||||
//
|
||||
//
|
||||
//
|
||||
//using namespace g2;
|
||||
//using namespace g2::internal;
|
||||
//
|
||||
//TEST(ConceptSink, CreateHandle) {
|
||||
// Worker worker;
|
||||
// auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
// ASSERT_NE(nullptr, handle.get());
|
||||
//}
|
||||
//
|
||||
//TEST(ConceptSink, OneSink__VerifyMsgIn) {
|
||||
// Worker worker;
|
||||
// auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
// worker.save("Hello World!");
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// auto output = handle->call(&CoutSink::string);
|
||||
// auto content = output.get();
|
||||
// auto pos = content.find("Hello World!");
|
||||
// ASSERT_NE(pos, std::string::npos);
|
||||
//}
|
||||
//
|
||||
//struct StringSink {
|
||||
// std::string raw;
|
||||
//
|
||||
// void append(g2::LogMessage entry) {
|
||||
// raw.append(entry.message());
|
||||
// }
|
||||
//
|
||||
// std::string string() {
|
||||
// return raw;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//TEST(ConceptSink, DualSink__VerifyMsgIn) {
|
||||
// Worker worker;
|
||||
// auto h1 = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
// auto h2 = worker.addSink(std2::make_unique<StringSink>(), &StringSink::append);
|
||||
// worker.save("Hello World!");
|
||||
//
|
||||
//
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// auto first = h1->call(&CoutSink::string);
|
||||
// auto second = h2->call(&StringSink::string);
|
||||
//
|
||||
//
|
||||
// ASSERT_EQ("Hello World!", first.get());
|
||||
// ASSERT_EQ("Hello World!", second.get());
|
||||
//}
|
||||
//
|
||||
//TEST(ConceptSink, DeletedSink__Exptect_badweak_ptr___exception) {
|
||||
// auto worker = std2::make_unique<Worker>();
|
||||
// auto h1 = worker->addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
// worker->save("Hello World!");
|
||||
// worker.reset();
|
||||
//
|
||||
// auto first = h1->call(&CoutSink::string);
|
||||
// EXPECT_THROW(first.get(), std::bad_weak_ptr);
|
||||
//}
|
||||
//
|
||||
//namespace {
|
||||
// typedef std::shared_ptr<std::atomic<bool>> AtomicBoolPtr;
|
||||
// typedef std::shared_ptr<std::atomic<int>> AtomicIntPtr;
|
||||
// typedef vector<AtomicBoolPtr> BoolList;
|
||||
// typedef vector<AtomicIntPtr> IntVector;
|
||||
//}
|
||||
//TEST(ConceptSink, OneHundredSinks) {
|
||||
// BoolList flags;
|
||||
// IntVector counts;
|
||||
//
|
||||
// size_t NumberOfItems = 100;
|
||||
// for(size_t index = 0; index < NumberOfItems; ++index) {
|
||||
// flags.push_back(make_shared<atomic<bool>>(false));
|
||||
// counts.push_back(make_shared<atomic<int>>(0));
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// auto worker = std::unique_ptr<Worker>(new Worker);
|
||||
// size_t index = 0;
|
||||
// for(auto& flag: flags) {
|
||||
// auto& count = counts[index++];
|
||||
// // ignore the handle
|
||||
// worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
// }
|
||||
// worker->save("Hello to 100 receivers :)");
|
||||
// worker->save("Hello to 100 receivers :)");
|
||||
// }
|
||||
// // at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
// // 100 logging receivers will get their message to exit after all messages are
|
||||
// // are processed
|
||||
// size_t index = 0;
|
||||
// for(auto& flag: flags) {
|
||||
// auto& count = counts[index++];
|
||||
// ASSERT_TRUE(flag->load()) << ", count : " << (index-1);
|
||||
// ASSERT_TRUE(2 == count->load()) << ", count : " << (index-1);
|
||||
// }
|
||||
//
|
||||
// cout << "test one hundred sinks is finished finished\n";
|
||||
//}
|
||||
//
|
||||
//
|
||||
///*
|
||||
//TEST(Sink, OneSink) {
|
||||
// AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
// AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
// {
|
||||
// auto worker = std::make_shared<g2LogWorker>();
|
||||
// worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
// worker->save("this message should trigger an atomic increment at the sink");
|
||||
//
|
||||
// EXPECT_FALSE(flag->load());
|
||||
// EXPECT_TRUE(0 == count->load());
|
||||
// }
|
||||
// EXPECT_TRUE(flag->load());
|
||||
// EXPECT_TRUE(1 == count->load());
|
||||
//}
|
||||
//
|
||||
//TEST(Sink, OneSinkWithHandleOutOfScope) {
|
||||
// AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
// AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
// {
|
||||
// auto worker = std::make_shared<g2LogWorker>();
|
||||
// {
|
||||
// auto handle = worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
// }
|
||||
// EXPECT_FALSE(flag->load());
|
||||
// EXPECT_TRUE(0 == count->load());
|
||||
// worker->save("this message should trigger an atomic increment at the sink");
|
||||
// }
|
||||
// EXPECT_TRUE(flag->load());
|
||||
// EXPECT_TRUE(1 == count->load());
|
||||
//}
|
||||
//
|
||||
////Perfect det här testet triggar felet
|
||||
//
|
||||
//typedef vector<AtomicBoolPtr> BoolPtrVector;
|
||||
//typedef vector<AtomicIntPtr> IntPtrVector;
|
||||
//TEST(Sink, OneHundredSinks) {
|
||||
// BoolPtrVector flags;
|
||||
// IntPtrVector counts;
|
||||
//
|
||||
// size_t NumberOfItems = 100;
|
||||
// for (size_t index = 0; index < NumberOfItems; ++index) {
|
||||
// flags.push_back(make_shared < atomic<bool >> (false));
|
||||
// counts.push_back(make_shared < atomic<int >> (0));
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// auto worker = std::make_shared<g2LogWorker>();
|
||||
// size_t index = 0;
|
||||
// for (auto& flag : flags) {
|
||||
// auto& count = counts[index++];
|
||||
// // ignore the handle
|
||||
// worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
// }
|
||||
// worker->save("Hello to 100 receivers :)");
|
||||
// }
|
||||
//
|
||||
// // at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
// // 100 logging receivers will get their message to exit after all messages are
|
||||
// // are processed // at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
// // 100 logging receivers will get their message to exit after all messages are
|
||||
// // are processed
|
||||
// size_t index = 0;
|
||||
// for (auto& flag : flags) {
|
||||
// auto& count = counts[index++];
|
||||
// EXPECT_TRUE(flag->load());
|
||||
// EXPECT_EQ(100, count->load());
|
||||
// cout << "test one hundred sinks is finished finished\n";
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//*/
|
||||
//
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
#include "testing_helpers.h"
|
||||
#include "std2_make_unique.hpp"
|
||||
#include "g2sink.h"
|
||||
#include "g2sinkwrapper.h"
|
||||
#include "g2sinkhandle.h"
|
||||
#include "g2logmessage.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace std2;
|
||||
using namespace testing_helpers;
|
||||
|
||||
class CoutSink {
|
||||
stringstream buffer;
|
||||
unique_ptr<ScopedOut> scope_ptr;
|
||||
|
||||
CoutSink() : scope_ptr(std2::make_unique<ScopedOut>(std::cout, &buffer)) {}
|
||||
public:
|
||||
void clear() { buffer.str(""); }
|
||||
std::string string() { return buffer.str(); }
|
||||
void save(g2::LogMessageMover msg) { std::cout << msg.get().message(); }
|
||||
virtual ~CoutSink() final {}
|
||||
static std::unique_ptr<CoutSink> createSink() { return std::unique_ptr<CoutSink>(new CoutSink);}
|
||||
};
|
||||
|
||||
struct StringSink {
|
||||
std::string raw;
|
||||
void append(g2::LogMessageMover entry) { raw.append(entry.get().message());}
|
||||
std::string string() {
|
||||
return raw;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
typedef std::shared_ptr<g2::internal::SinkWrapper> SinkWrapperPtr;
|
||||
}
|
||||
|
||||
namespace g2 {
|
||||
|
||||
class Worker {
|
||||
std::vector<SinkWrapperPtr> _container; // should be hidden in a pimple with a bg active object
|
||||
std::unique_ptr<kjellkod::Active> _bg;
|
||||
|
||||
void bgSave(std::string msg) {
|
||||
for (auto& sink : _container) {
|
||||
g2::LogMessage message("test", 0, "test", DEBUG);
|
||||
message.write().append(msg);
|
||||
sink->send(LogMessageMover(std::move(message)));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Worker() : _bg {
|
||||
kjellkod::Active::createActive()
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
~Worker() {
|
||||
_bg->send([this] {
|
||||
_container.clear(); });
|
||||
}
|
||||
|
||||
void save(std::string msg) {
|
||||
_bg->send([this, msg] { bgSave(msg); });
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename DefaultLogCall>
|
||||
std::unique_ptr< SinkHandle<T> > addSink(std::unique_ptr<T> unique, DefaultLogCall call) {
|
||||
auto shared = std::shared_ptr<T>(unique.release());
|
||||
auto sink = std::make_shared < internal::Sink<T> > (shared, call);
|
||||
auto add_sink_call = [this, sink] { _container.push_back(sink); };
|
||||
|
||||
auto wait_result = g2::spawn_task(add_sink_call, _bg.get());
|
||||
wait_result.wait();
|
||||
|
||||
auto handle = std2::make_unique< SinkHandle<T> >(sink);
|
||||
return handle;
|
||||
}
|
||||
};
|
||||
|
||||
} // g2
|
||||
|
||||
|
||||
|
||||
using namespace g2;
|
||||
using namespace g2::internal;
|
||||
|
||||
TEST(ConceptSink, CreateHandle) {
|
||||
Worker worker;
|
||||
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
ASSERT_NE(nullptr, handle.get());
|
||||
}
|
||||
|
||||
TEST(ConceptSink, OneSink__VerifyMsgIn) {
|
||||
Worker worker;
|
||||
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
worker.save("Hello World!");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto output = handle->call(&CoutSink::string);
|
||||
auto content = output.get();
|
||||
auto pos = content.find("Hello World!");
|
||||
ASSERT_NE(pos, std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
TEST(ConceptSink, DualSink__VerifyMsgIn) {
|
||||
Worker worker;
|
||||
auto h1 = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
auto h2 = worker.addSink(std2::make_unique<StringSink>(), &StringSink::append);
|
||||
worker.save("Hello World!");
|
||||
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto first = h1->call(&CoutSink::string);
|
||||
auto second = h2->call(&StringSink::string);
|
||||
|
||||
|
||||
ASSERT_EQ("Hello World!", first.get());
|
||||
ASSERT_EQ("Hello World!", second.get());
|
||||
}
|
||||
|
||||
TEST(ConceptSink, DeletedSink__Exptect_badweak_ptr___exception) {
|
||||
auto worker = std2::make_unique<Worker>();
|
||||
auto h1 = worker->addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
worker->save("Hello World!");
|
||||
worker.reset();
|
||||
|
||||
auto first = h1->call(&CoutSink::string);
|
||||
EXPECT_THROW(first.get(), std::bad_weak_ptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
typedef std::shared_ptr<std::atomic<bool >> AtomicBoolPtr;
|
||||
typedef std::shared_ptr<std::atomic<int >> AtomicIntPtr;
|
||||
typedef vector<AtomicBoolPtr> BoolList;
|
||||
typedef vector<AtomicIntPtr> IntVector;
|
||||
}
|
||||
|
||||
TEST(ConceptSink, OneHundredSinks) {
|
||||
BoolList flags;
|
||||
IntVector counts;
|
||||
|
||||
size_t NumberOfItems = 100;
|
||||
for (size_t index = 0; index < NumberOfItems; ++index) {
|
||||
flags.push_back(make_shared < atomic<bool >> (false));
|
||||
counts.push_back(make_shared < atomic<int >> (0));
|
||||
}
|
||||
|
||||
{
|
||||
auto worker = std::unique_ptr<Worker>(new Worker);
|
||||
size_t index = 0;
|
||||
for (auto& flag : flags) {
|
||||
auto& count = counts[index++];
|
||||
// ignore the handle
|
||||
worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
}
|
||||
worker->save("Hello to 100 receivers :)");
|
||||
worker->save("Hello to 100 receivers :)");
|
||||
}
|
||||
// at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
// 100 logging receivers will get their message to exit after all messages are
|
||||
// are processed
|
||||
size_t index = 0;
|
||||
for (auto& flag : flags) {
|
||||
auto& count = counts[index++];
|
||||
ASSERT_TRUE(flag->load()) << ", count : " << (index - 1);
|
||||
ASSERT_TRUE(2 == count->load()) << ", count : " << (index - 1);
|
||||
}
|
||||
|
||||
cout << "test one hundred sinks is finished finished\n";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
TEST(Sink, OneSink) {
|
||||
AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
{
|
||||
auto worker = std::make_shared<g2LogWorker>();
|
||||
worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
worker->save("this message should trigger an atomic increment at the sink");
|
||||
|
||||
EXPECT_FALSE(flag->load());
|
||||
EXPECT_TRUE(0 == count->load());
|
||||
}
|
||||
EXPECT_TRUE(flag->load());
|
||||
EXPECT_TRUE(1 == count->load());
|
||||
}
|
||||
|
||||
TEST(Sink, OneSinkWithHandleOutOfScope) {
|
||||
AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
{
|
||||
auto worker = std::make_shared<g2LogWorker>();
|
||||
{
|
||||
auto handle = worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
}
|
||||
EXPECT_FALSE(flag->load());
|
||||
EXPECT_TRUE(0 == count->load());
|
||||
worker->save("this message should trigger an atomic increment at the sink");
|
||||
}
|
||||
EXPECT_TRUE(flag->load());
|
||||
EXPECT_TRUE(1 == count->load());
|
||||
}
|
||||
|
||||
//Perfect det här testet triggar felet
|
||||
|
||||
typedef vector<AtomicBoolPtr> BoolPtrVector;
|
||||
typedef vector<AtomicIntPtr> IntPtrVector;
|
||||
TEST(Sink, OneHundredSinks) {
|
||||
BoolPtrVector flags;
|
||||
IntPtrVector counts;
|
||||
|
||||
size_t NumberOfItems = 100;
|
||||
for (size_t index = 0; index < NumberOfItems; ++index) {
|
||||
flags.push_back(make_shared < atomic<bool >> (false));
|
||||
counts.push_back(make_shared < atomic<int >> (0));
|
||||
}
|
||||
|
||||
{
|
||||
auto worker = std::make_shared<g2LogWorker>();
|
||||
size_t index = 0;
|
||||
for (auto& flag : flags) {
|
||||
auto& count = counts[index++];
|
||||
// ignore the handle
|
||||
worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
}
|
||||
worker->save("Hello to 100 receivers :)");
|
||||
}
|
||||
|
||||
// at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
// 100 logging receivers will get their message to exit after all messages are
|
||||
// are processed // at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
// 100 logging receivers will get their message to exit after all messages are
|
||||
// are processed
|
||||
size_t index = 0;
|
||||
for (auto& flag : flags) {
|
||||
auto& count = counts[index++];
|
||||
EXPECT_TRUE(flag->load());
|
||||
EXPECT_EQ(100, count->load());
|
||||
cout << "test one hundred sinks is finished finished\n";
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
@ -23,7 +23,7 @@ using namespace g2;
|
||||
EXPECT_TRUE(0 == count->load());
|
||||
//worker->save("this message should trigger an atomic increment at the sink");
|
||||
LogMessagePtr message{std2::make_unique<LogMessage>("test", 0, "test", DEBUG)};
|
||||
message.get()->stream() << "this message should trigger an atomic increment at the sink";
|
||||
message.get()->write().append("this message should trigger an atomic increment at the sink");
|
||||
worker->save(message);
|
||||
}
|
||||
EXPECT_TRUE(flag->load());
|
||||
@ -61,15 +61,13 @@ TEST(ConceptSink, OneHundredSinks) {
|
||||
LOG(DEBUG) << "start message";
|
||||
LogMessagePtr message1{std2::make_unique<LogMessage>("test", 0, "test", DEBUG)};
|
||||
LogMessagePtr message2{std2::make_unique<LogMessage>("test", 0, "test", DEBUG)};
|
||||
auto& stream1 = message1.get()->stream();
|
||||
stream1 << "Hello to 100 receivers :)";
|
||||
auto& write1 = message1.get()->write();
|
||||
write1.append("Hello to 100 receivers :)");
|
||||
worker->save(message1);
|
||||
|
||||
auto& stream2 = message2.get()->stream();
|
||||
stream2 << "Hello to 100 receivers :)";
|
||||
auto& write2 = message2.get()->write();
|
||||
write2.append("Hello to 100 receivers :)");
|
||||
worker->save(message2);
|
||||
//worker->save("Hello to 100 receivers :)");
|
||||
//worker->save("Hello to 100 receivers :)");
|
||||
LOG(INFO) << "end message";
|
||||
}
|
||||
// at the curly brace above the ScopedLogger will go out of scope and all the
|
||||
|
Loading…
Reference in New Issue
Block a user