fixing compile errors after large conceptual remake

This commit is contained in:
KjellKod 2013-11-02 10:01:18 -06:00
parent 4adbd1c065
commit 81b6b91038
16 changed files with 364 additions and 95 deletions

View File

@ -7,6 +7,7 @@
#include "crashhandler.hpp"
#include "g2log.hpp"
#include "g2logmessage.hpp"
#include "g2LogMessageBuilder.hpp"
#include <csignal>
#include <cstring>
@ -41,14 +42,13 @@ namespace {
fatal_stream << oss.str() << std::endl;
fatal_stream << "\n***** SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
FatalMessage fatal_message(fatal_stream.str(), signal_number);
const auto& crashMessage = fatal_message._crash_message;
std::cerr << crashMessage.toString() << std::endl << std::flush;
//g2::FatalMessage fatal_message{fatal_stream.str(), signal_number};
//const auto& crashMessage = fatal_message._crash_message;
std::cerr << fatal_stream.str() << std::flush;
FatalTrigger trigger(fatal_message);
std::ostringstream oss;
} // message sent to g2LogWorker by FatalTrigger
// wait to die -- will be inside the FatalTrigger
g2::FatalMessageBuilder trigger(fatal_stream.str(), signal_number);
} // message sent to g2LogWorker by FatalMessageBuilder
// wait to die -- will be inside the FatalMessageBuilder
}
} // end anonymous namespace

View File

@ -27,7 +27,7 @@ void crashHandler(int signal_number)
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message); std::ostringstream oss;
FatalMessageBuilder trigger(fatal_message); std::ostringstream oss;
std::cerr << fatal_message.message_ << std::endl << std::flush;
} // scope exit - message sent to LogWorker, wait to die...
} // end anonymous namespace

View File

@ -0,0 +1,56 @@
/*
* File: MessageBuilder.cpp
* Author: kjell
*
* Created on October 26, 2013, 3:45 PM
*/
#include "g2LogMessageBuilder.hpp"
#include "g2logmessageimpl.hpp"
#include "g2log.hpp"
#include "g2logmessage.hpp"
#include <iostream>
#include <csignal>
namespace g2 {
LogMessageBuilder::LogMessageBuilder(const std::string& file, const int line,
const std::string& function, const LEVELS& level)
: _message(std::make_shared<LogMessageImpl>(file, line, function, level)) {}
//: _message(new LogMessageImpl(file, line, function, level)) //
//{}
LogMessageBuilder::~LogMessageBuilder() {
LogMessage log_entry(_message);
if (log_entry.wasFatal()) {
FatalMessageBuilder trigger({log_entry.toString(), SIGABRT});
return; // FatalMessageBuilder will send to worker at scope exit
}
internal::saveMessage(log_entry); // message saved to g2LogWorker
}
LogMessageBuilder& LogMessageBuilder::setExpression(const std::string& boolean_expression) {
_message->_expression = boolean_expression;
return *this;
}
std::ostringstream& LogMessageBuilder::stream() {
return _message->_stream;
}
/// FatalMessageBuilder
FatalMessageBuilder::FatalMessageBuilder(const std::string& exit_message, int fatal_signal)
:_exit_message(exit_message), _fatal_signal(fatal_signal) { }
FatalMessageBuilder::~FatalMessageBuilder() {
// At destruction, flushes fatal message to g2LogWorker
// either we will stay here until the background worker has received the fatal
// message, flushed the crash message to the sinks and exits with the same fatal signal
//..... OR it's in unit-test mode then we throw a std::runtime_error (and never hit sleep)
internal::fatalCall({_exit_message, _fatal_signal});
}
} // g2

View File

@ -0,0 +1,48 @@
/*
* File: MessageBuilder.hpp
* Author: kjell
*
* Created on October 26, 2013, 3:45 PM
*/
#pragma once
#include <string>
#include <sstream>
#include <memory>
#include <cstdarg>
#include "g2loglevels.hpp"
namespace g2 {struct LogMessageImpl;
// At RAII scope end this struct will trigger a FatalMessage sending
struct FatalMessageBuilder {
//explicit FatalMessageBuilder(const FatalMessage& exit_message);
FatalMessageBuilder(const std::string& exit_message, int fatal_signal);
~FatalMessageBuilder();
std::string _exit_message;
int _fatal_signal;
};
struct LogMessageBuilder {
LogMessageBuilder(const std::string& file, const int line, const std::string& function, const LEVELS& level);
virtual ~LogMessageBuilder();
LogMessageBuilder& setExpression(const std::string& boolean_expression);
std::ostringstream& stream();
// Use "-Wall" to generate warnings in case of illegal printf format.
// Ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
#ifndef __GNUC__
#define __attribute__(x) // Disable 'attributes' if compiler does not support 'em
#endif
void messageSave(const char *printf_like_message, ...)
__attribute__((format(printf, 2, 3))); // ref: http://www.codemaestro.com/reviews/18
private:
std::shared_ptr<LogMessageImpl> _message;
};
} // g2

View File

@ -17,8 +17,7 @@
* ********************************************* */
#ifndef G2LOG_H
#define G2LOG_H
#pragma once
#include <string>
#include <cstdarg>
@ -46,14 +45,23 @@ class g2LogWorker;
*/
namespace g2 {
struct LogMessage;
struct FatalMessage;
/** Should be called at very first startup of the software with \ref g2LogWorker
* pointer. Ownership of the \ref g2LogWorker is the responsibilkity of the caller */
void initializeLogging(g2LogWorker *logger);
namespace internal {
// Save the created LogMessage to any existing sinks
void saveMessage(const g2::LogMessage& log_entry);
void saveMessage(g2::LogMessage log_entry);
// Save the created FatalMessage to any existing sinks and exit with
// the originating fatal signal,. or SIGABRT if it originated from a broken contract
void fatalCall(FatalMessage message);
/** FOR TESTING PURPOSES
* Shutdown the logging by making the pointer to the background logger to nullptr
@ -72,21 +80,18 @@ bool isLoggingInitialized();
* test of FATAL level cumbersome. A work around is to change the
* fatal call' which can be done here */
void changeFatalInitHandlerForUnitTesting();
} // end namespace internal
} // end namespace g2
} // g2::internal
} // g2
#define INTERNAL_LOG_MESSAGE(level) g2::internal::LogMessageBuilder(__FILE__, __LINE__, __PRETTY_FUNCTION__, level)
#define INTERNAL_LOG_MESSAGE(level) g2::LogMessageBuilder(__FILE__, __LINE__, __PRETTY_FUNCTION__, level)
//LogMessageBuilder(const char* file, const int line, const char* function, const LEVELS& level){}
#define INTERNAL_CONTRACT_MESSAGE(boolean_expression) \
g2::internal::LogMessageBuilder(__FILE__, __LINE__, __PRETTY_FUNCTION__, ::FATAL)
//.setExpression(boolean_expression)
g2::LogMessageBuilder(__FILE__, __LINE__, __PRETTY_FUNCTION__, FATAL).setExpression(boolean_expression)
// LOG(level) is the API for the stream log
@ -165,4 +170,4 @@ And here is possible output
#define CHECK_F(boolean_expression, printf_like_message, ...) \
if (false == (boolean_expression)) INTERNAL_CONTRACT_MESSAGE(#boolean_expression).messageSave(printf_like_message, ##__VA_ARGS__)
#endif // G2LOG_H

95
g2log/src/g2log.ipp Normal file
View File

@ -0,0 +1,95 @@
/*
* File: g2logg.ipp
* Author: kjell
*
* Created on October 20, 2013, 8:47 PM
*/
#pragma once
#include "g2log.hpp"
#include "g2logmessage.hpp"
#include "g2logworker.hpp"
#include "g2logmessageimpl.hpp"
#include "g2loglevels.hpp"
#include <cassert>
#include <memory>
#include <mutex>
#include <thread>
#include <chrono>
namespace g2 {
namespace internal {
g2LogWorker* g_logger_instance = nullptr; // instantiated and OWNED somewhere else (main)
std::string g_once_error;
std::once_flag g_error_flag;
std::once_flag g_retrieve_error_flag;
}
/**
* saveMesage to the LogWorker which will pass them to the sinks.
*
* In the messup of calling LOG before instantiating the logger the first
* message will be saved,.. to be given later with an initialization warning
*/
void saveMessage(g2::LogMessage log_entry) {
using namespace internal;
if (false == isLoggingInitialized()) {
std::call_once(g_error_flag, [&]() {
g_once_error = {"\n\nWARNING LOGGER NOT INSTANTIATED WHEN CALLING IT"
"\nAt least once tried to call the logger before instantiating it\n\n"};
g_once_error.append("\nThe first message was: \n").append(log_entry.toString());
});
std::cerr << g_once_error << std::endl;
return;
}
std::call_once(g_retrieve_error_flag, [&]() {
if (false == g_once_error.empty()) {
std::string empty = {""};
g2::LogMessage error{std::make_shared<g2::LogMessageImpl>(empty, 0, empty, WARNING)};
error.stream() << g_once_error;
g_logger_instance->save(error);
}
});
g_logger_instance->save(log_entry);
}
void fatalCallToLogger(FatalMessage message) {
// real fatal call to loggr
internal::g_logger_instance->fatal(message);
}
// By default this function pointer goes to \ref fatalCall;
void (*g_fatal_to_g2logworker_function_ptr)(FatalMessage) = fatalCallToLogger;
void fatalCallForUnitTest(FatalMessage fatal_message) {
// mock fatal call, not to logger: used by unit test
assert(internal::g_logger_instance != nullptr);
internal::g_logger_instance->save(fatal_message.copyToLogMessage()); // calling 'save' instead of 'fatal'
throw std::runtime_error(fatal_message.toString());
}
/** The default, initial, handling to send a 'fatal' event to g2logworker
* he caller will stay here, eternally, until the software is aborted
* During unit testing the sleep-loop will be interrupted by exception from
* @ref fatalCallForUnitTest */
void fatalCall(FatalMessage message) {
g_fatal_to_g2logworker_function_ptr(message);
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
/** Used to REPLACE fatalCallToLogger for fatalCallForUnitTest
* This function switches the function pointer so that only
* 'unitTest' mock-fatal calls are made. */
void changeFatalInitHandlerForUnitTesting() {
g_fatal_to_g2logworker_function_ptr = fatalCallForUnitTest;
}
} // g2

View File

@ -10,11 +10,12 @@
* ********************************************* */
#include "g2logmessage.hpp"
#include "g2logmessageimpl.hpp"
#include "g2time.hpp"
#include "crashhandler.hpp"
#include <stdexcept> // exceptions
#include "g2log.hpp"
#include "g2log.ipp"
namespace g2 {
@ -76,7 +77,7 @@ namespace g2 {
std::ostringstream oss;
oss << "\n" << timestamp() << "." << microseconds() << "\t";
oss << level() << " [" << file();
oss << " L: " << line() << "]\t";
@ -116,31 +117,20 @@ namespace g2 {
}
LogMessage(std::shared_ptr<LogMessageImpl> details)
LogMessage::LogMessage(std::shared_ptr<LogMessageImpl> details)
: _pimpl(details) { }
namespace internal {
FatalMessage::FatalMessage(const std::string& crash_message, int signal_id)
: LogMessage(std::make_shared<LogMessageImpl>(crash_message)), signal_id_(signal_id)
{ }
FatalMessage::FatalMessage(const std::string& crash_message, int signal_id)
: FatalMessage({std::make_shared<LogMessageImpl>(crash_message)}, signal_id) { }
LogMessage FatalMessage::copyToLogMessage() const {
return LogMessage(_pimpl);
}
//FatalMessage(const LogMessage& message, int signal_id)
//: _crash_message(message), signal_id_(signal_id) { }
FatalMessage(const LogMessage& message, int signal_id)
: _crash_message(message), signal_id_(signal_id) { }
FatalTrigger::FatalTrigger(const FatalMessage& exit_message) : _fatal_message(exit_message) { }
FatalTrigger::~FatalTrigger() {
// At destruction, flushes fatal message to g2LogWorker
// either we will stay here until the background worker has received the fatal
// message, flushed the crash message to the sinks and exits with the same fatal signal
//..... OR it's in unit-test mode then we throw a std::runtime_error (and never hit sleep)
fatalCall(_fatal_message);
}
} // internal
} // g2

View File

@ -21,52 +21,45 @@
#include "g2log.hpp"
#include "g2loglevels.hpp"
#include "g2time.hpp"
//#include "g2logmessageimpl.hpp"
namespace g2 {
struct LogMessageImpl;
struct LogMessageImpl;
struct LogMessage {
mutable std::shared_ptr<LogMessageImpl> _pimpl;
std::string file() const;
std::string line() const;
std::string function() const;
std::string level() const;
std::string timestamp(const std::string& time_format = {internal::date_formatted + " " + internal::time_formatted}) const;
std::string microseconds() const;
std::string message() const;
std::string expression() const;
bool wasFatal() const;
// convert all content to ONE string
std::string toString() const;
struct LogMessage {
mutable std::shared_ptr<LogMessageImpl> _pimpl;
std::string file() const;
std::string line() const;
std::string function() const;
std::string level() const;
std::string timestamp(const std::string& time_format = {internal::date_formatted + " " + internal::time_formatted}) const;
std::string microseconds() const;
std::string message() const;
std::string expression() const;
std::ostringstream& stream();
explicit LogMessage(std::shared_ptr<LogMessageImpl> details);
~LogMessage() = default;
};
bool wasFatal() const;
// convert all content to ONE string
std::string toString() const;
std::ostringstream& stream();
explicit LogMessage(std::shared_ptr<LogMessageImpl> details);
~LogMessage() = default;
};
namespace internal {
/** Trigger for flushing the message queue and exiting the application
* A thread that causes a FatalMessage will sleep forever until the
* application has exited (after message flush) */
struct FatalMessage {
struct FatalMessage : public LogMessage {
FatalMessage(const std::string& message, int signal_id);
FatalMessage(const LogMessage& message, int signal_id);
//FatalMessage(const LogMessage& message, int signal_id);
~FatalMessage() = default;
mutable LogMessage _crash_message;
LogMessage copyToLogMessage() const;
//mutable LogMessage _crash_message;
int signal_id_;
};
// At RAII scope end this struct will trigger a FatalMessage sending
struct FatalTrigger {
explicit FatalTrigger(const FatalMessage& exit_message);
~FatalTrigger();
FatalMessage _fatal_message;
};
} // internal
} // g2

View File

@ -0,0 +1,39 @@
#include <g2logmessageimpl.hpp>
#include <g2time.hpp>
#include <mutex>
namespace {
const int kMaxMessageSize = 2048;
const std::string kTruncatedWarningText = "[...truncated...]";
std::once_flag g_start_time_flag;
g2::steady_time_point g_start_time;
long microsecondsCounter() {
std::call_once(g_start_time_flag, []() { g_start_time = std::chrono::steady_clock::now(); });
g2::steady_time_point now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(g_start_time - now).count();
}
std::string splitFileName(const std::string& str) {
size_t found;
found = str.find_last_of("(/\\");
return str.substr(found + 1);
}
} // anonymous
namespace g2 {
LogMessageImpl::LogMessageImpl(const std::string &file, const int line,
const std::string& function, const LEVELS& level)
: _timestamp(g2::systemtime_now())
, _microseconds(microsecondsCounter())
, _file(splitFileName(file)), _line(line), _function(function), _level(level) { }
LogMessageImpl::LogMessageImpl(const std::string& fatalOsSignalCrashMessage)
: LogMessageImpl({""}, 0, {""}, internal::FATAL_SIGNAL) {
_stream << fatalOsSignalCrashMessage;
}
} // g2

View File

@ -0,0 +1,39 @@
// -*- C++ -*-
/*
* File: g2logmessageimpl.hpp
* Author: kjell
*
* Created on October 27, 2013, 9:14 PM
*/
#pragma once
#include <string>
#include "g2loglevels.hpp"
#include <ctime>
#include <sstream>
namespace g2 {
struct LogMessageImpl {
// LOG message constructor
LogMessageImpl(const std::string &file, const int line,
const std::string& function, const LEVELS& level);
// Fatal OS-Signal constructor
explicit LogMessageImpl(const std::string& fatalOsSignalCrashMessage);
~LogMessageImpl() = default;
const std::time_t _timestamp;
const long _microseconds;
const std::string _file;
const int _line;
const std::string _function;
const LEVELS _level;
std::string _expression; // only with content for CHECK(...) calls
std::ostringstream _stream;
};
}

View File

@ -39,7 +39,7 @@ struct g2LogWorkerImpl {
std::cout << "g2logworker active object destroyed. done sending exit messages to all sinks\n";
}
void bgSave(const g2::LogMessage& msg) {
void bgSave(g2::LogMessage msg) {
for (auto& sink : _sinks) {
sink->send(msg);
}
@ -51,12 +51,13 @@ struct g2LogWorkerImpl {
}
}
void bgFatal(g2::internal::FatalMessage fatal_message) {
auto entry = fatal_message._crash_message;
entry.stream() << "\nExiting after fatal event. Log flushed sucessfully to disk.\n";
bgSave(entry);
void bgFatal(FatalMessage msg) {
//auto entry = fatal_message._crash_message;
auto fatal_message = msg;
fatal_message.stream() << "\nExiting after fatal event. Log flushed sucessfully to disk.\n";
bgSave(fatal_message.copyToLogMessage());
std::cerr << entry.toString() << std::endl;
std::cerr << fatal_message.toString() << std::endl;
std::cerr << "g2log sinks are flushed. Now exiting after receiving fatal event\n" << std::flush;
_sinks.clear(); // flush all queues
exitWithDefaultSignalHandler(fatal_message.signal_id_);
@ -78,11 +79,11 @@ g2LogWorker::~g2LogWorker() {
_pimpl->_bg->send([this]{_pimpl->_sinks.clear();});
}
// todo move operator
void g2LogWorker::save(g2::LogMessage msg) {
void g2LogWorker::save(LogMessage msg) {
_pimpl->_bg->send([this, msg] { _pimpl->bgSave(msg); }); // TODO std::move
}
void g2LogWorker::fatal(g2::internal::FatalMessage fatal_message) {
void g2LogWorker::fatal(FatalMessage fatal_message) {
_pimpl->_bg->send([this, fatal_message] {_pimpl->bgFatal(fatal_message); });
}

View File

@ -61,7 +61,7 @@ public:
/// Will push a fatal message on the queue, this is the last message to be processed
/// this way it's ensured that all existing entries were flushed before 'fatal'
/// Will abort the application!
void fatal(g2::internal::FatalMessage fatal_message);
void fatal(g2::FatalMessage fatal_message);
template<typename T, typename DefaultLogCall>
std::unique_ptr<g2::SinkHandle<T >> addSink(std::unique_ptr<T> real_sink, DefaultLogCall call) {

View File

@ -58,7 +58,7 @@ struct Sink : public SinkWrapper {
_bg.reset(); // TODO: to remove
}
void send(LogMessage msg) override {
void send(const LogMessage& msg) override {
_bg->send([this, msg] {
_default_log_call(msg);
});

View File

@ -15,7 +15,7 @@ namespace g2 {
struct SinkWrapper {
virtual ~SinkWrapper() { }
virtual void send(LogMessage msg) = 0;
virtual void send(const LogMessage& msg) = 0;
};
}
}

View File

@ -13,6 +13,7 @@
#include "g2sinkwrapper.h"
#include "g2sinkhandle.h"
#include "g2logmessage.hpp"
#include "g2logmessageimpl.hpp"
using namespace std;
@ -35,7 +36,7 @@ public:
return buffer.str();
}
void save(g2::internal::LogEntry msg) {
void save(std::string msg) {
std::cout << msg;
}
@ -50,7 +51,7 @@ public:
namespace {
typedef std::shared_ptr<g2::internal::SinkWrapper> SinkWrapperPtr;
typedef g2::internal::LogEntry LogEntry;
typedef std::string LogEntry;
}
namespace g2 {
@ -61,7 +62,9 @@ namespace g2 {
void bgSave(LogEntry msg) {
for (auto& sink : _container) {
sink->send(msg);
g2::LogMessage message(std::make_shared<g2::LogMessageImpl>("test", 0, "test", DEBUG));
message.stream() << msg;
sink->send(message);
}
}

View File

@ -42,13 +42,13 @@ namespace testing_helpers {
ScopedLogger::ScopedLogger()
: _previousWorker(g2::shutDownLogging())
: _previousWorker(g2::internal::shutDownLogging())
, _currentWorker(g2LogWorker::createWithNoSink()) {
g2::initializeLogging(_currentWorker.get());
}
ScopedLogger::~ScopedLogger() {
auto* current = g2::shutDownLogging();
auto* current = g2::internal::shutDownLogging();
CHECK(current == _currentWorker.get());
if (nullptr != _previousWorker) {
g2::initializeLogging(_previousWorker);