Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gimesketvirtadien's time requested changes #104

Merged
merged 34 commits into from
Aug 11, 2016
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c9cee5d
Added "removeSink" method and related functionality to LogWorker API
gimesketvirtadieni May 8, 2016
2a632ff
Added a new API for plugging in custom Timestamp generator.
gimesketvirtadieni May 8, 2016
0096d37
Revert "Added "removeSink" method and related functionality to LogWor…
gimesketvirtadieni May 8, 2016
0f07288
Dropping shared_ptr<Timestamp> in log messages and using regular vars
gimesketvirtadieni Jun 6, 2016
fd8c3ed
Moving to standard timespec struct from custom Timestamp
gimesketvirtadieni Jun 13, 2016
ebcd6f7
Wiring timespec timestamps with formating routine
gimesketvirtadieni Jun 19, 2016
8f449b0
Falling back to clock_gettime
gimesketvirtadieni Jun 19, 2016
b6fe945
Reverting g3 API changes
gimesketvirtadieni Jun 23, 2016
000e382
Optimizing format string generation
gimesketvirtadieni Jun 24, 2016
50487bf
Merge branch 'upstream' of github.com:gimesketvirtadieni/g3log into g…
Jun 25, 2016
3d40861
Removed _microseconds from LogMessage
gimesketvirtadieni Jun 25, 2016
73947c3
Implemented sec fractional format key
gimesketvirtadieni Jun 27, 2016
cfaffe3
Optimization of format string generation
gimesketvirtadieni Jun 28, 2016
4f8c7bd
Adjusting comments
gimesketvirtadieni Jun 28, 2016
141d955
Refining localtime_formatted by introducing two helper functions
gimesketvirtadieni Jul 1, 2016
03fc0e9
Merge branch 'upstream' of github.com:gimesketvirtadieni/g3log into g…
Jul 3, 2016
985ca75
refactored and simplified code
Jul 3, 2016
59e00d5
fixed up some commented away unit tests
Jul 18, 2016
4dc5580
refactoring message specifics tests to it's own test
Jul 18, 2016
bd9fd04
Use gcc 4.9
Jul 18, 2016
38b87b1
C++14 for Linux
Jul 18, 2016
72e18de
Update .travis.yml
Jul 18, 2016
12a5977
Update buildAndRunTests.sh
Jul 18, 2016
fe560ad
lower case in `-std=c++14`
Jul 18, 2016
60c0081
-lrt flag for gcc
Jul 18, 2016
2d4e900
Added support for high precision clock on Linux/gcc (already there no…
Jul 18, 2016
b825886
intermediate comments
Jul 18, 2016
f1439d3
Clarified for some code readers the mysterious use of assert in an ex…
Jul 29, 2016
3b90e26
refactored + renamed functions and constants. Added unit test for ret…
Jul 29, 2016
e6c66c5
committing changes previously fixed - finished unit testing for g3::i…
Jul 29, 2016
0c05e29
added unit test for fractional to string
Aug 10, 2016
9d06bdd
added missing unit tests for localtime_formatted
Aug 10, 2016
af96b55
fixed? nano / microsec functionality to timer
Aug 11, 2016
10bc655
test
Aug 11, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/filesinkhelper.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace g3 {
// Day Month Date Time Year: is written as "%a %b %d %H:%M:%S %Y" and formatted output as : Wed Sep 19 08:28:16 2012
ss_entry << "\t\tg3log created log at: " << g3::localtime_formatted(g3::systemtime_now(), "%a %b %d %H:%M:%S %Y") << "\n";
ss_entry << "\t\tLOG format: [YYYY/MM/DD hh:mm:ss uuu* LEVEL FILE->FUNCTION:LINE] message";
ss_entry << "\t\t(uuu*: microsecond counter since initialization of log worker)\n\n";
ss_entry << "\t\t(uuu*: microseconds fractions of the seconds value)\n\n";
return ss_entry.str();
}

Expand Down
3 changes: 0 additions & 3 deletions src/g3log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ namespace g3 {
}





namespace internal {

bool isLoggingInitialized() {
Expand Down
8 changes: 1 addition & 7 deletions src/g3log/logmessage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ namespace g3 {
/// use a different format string to get a different look on the time.
// default look is Y/M/D H:M:S
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 _message;
Expand Down Expand Up @@ -87,9 +84,8 @@ namespace g3 {
// Complete access to the raw data in case the helper functions above
// are not enough.
//
std::time_t _timestamp;
timespec _timestamp;
std::thread::id _call_thread_id;
int64_t _microseconds;
std::string _file;
int _line;
std::string _function;
Expand All @@ -103,7 +99,6 @@ namespace g3 {
using std::swap;
swap(first._timestamp, second._timestamp);
swap(first._call_thread_id, second._call_thread_id);
swap(first._microseconds, second._microseconds);
swap(first._file, second._file);
swap(first._line, second._line);
swap(first._function, second._function);
Expand All @@ -116,7 +111,6 @@ namespace g3 {




/** 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) */
Expand Down
14 changes: 13 additions & 1 deletion src/g3log/time.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,26 @@ namespace g3
namespace internal
{
static const std::string date_formatted = "%Y/%m/%d";
static const std::string time_formatted = "%H:%M:%S";
// %f: fractions of seconds (%f is nanoseconds)
// %f3: milliseconds, 3 digits: 001
// %6: microseconds: 6 digits: 000001 --- default for the time_format
// %f9, %f: nanoseconds, 9 digits: 000000001
static const std::string time_formatted = "%H:%M:%S %f6";
}

typedef std::chrono::time_point<std::chrono::system_clock> system_time_point;
typedef std::chrono::milliseconds milliseconds;
typedef std::chrono::microseconds microseconds;

size_t time_fraction(const std::string& format_buffer, size_t pos);

// wrap for std::chrono::system_clock::now()
std::time_t systemtime_now();

// OSX, Windows needed wrapper for std::timespec_get(struct timespec *ts, int base)
// OSX and Windows also lacks the POSIX clock_gettime(int base, struct timespec *ts)
// so for that reason we go with the std::timespec_get(...) but wrap it
int timespec_get(struct timespec *ts/*, int base*/);

/** return time representing POD struct (ref ctime + wchar) that is normally
* retrieved with std::localtime. g3::localtime is threadsafe which std::localtime is not.
Expand All @@ -45,6 +56,7 @@ namespace g3
* WARNING: At time of writing there is only so-so compiler support for
* std::put_time. A possible fix if your c++11 library is not updated is to
* modify this to use std::strftime instead */
std::string localtime_formatted(const timespec &time_snapshot, const std::string &time_format) ;
std::string localtime_formatted(const std::time_t &time_snapshot, const std::string &time_format) ;
}

Expand Down
34 changes: 13 additions & 21 deletions src/logmessage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,6 @@
#include <mutex>

namespace {
std::once_flag g_start_time_flag;
std::chrono::steady_clock::time_point g_start_time;

int64_t microsecondsCounter() {
std::call_once(g_start_time_flag, []() {
g_start_time = std::chrono::steady_clock::now();
});
auto now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(now - g_start_time).count();
}

std::string splitFileName(const std::string& str) {
size_t found;
found = str.find_last_of("(/\\");
Expand All @@ -38,7 +27,7 @@ namespace g3 {
// helper for setting the normal log details in an entry
std::string LogDetailsToString(const LogMessage& msg) {
std::string out;
out.append("\n" + msg.timestamp() + " " + msg.microseconds() + "\t"
out.append("\n" + msg.timestamp() + "\t"
+ msg.level() + " [" + msg.file() + "->" + msg.function() + ":" + msg.line() + "]\t");
return out;
}
Expand All @@ -54,7 +43,7 @@ namespace g3 {
// helper for fatal signal
std::string fatalSignalToString(const LogMessage& msg) {
std::string out; // clear any previous text and formatting
out.append("\n" + msg.timestamp() + "." + msg.microseconds()
out.append("\n" + msg.timestamp()
+ "\n\n***** FATAL SIGNAL RECEIVED ******* \n"
+ '"' + msg.message() + '"');
return out;
Expand All @@ -64,7 +53,7 @@ namespace g3 {
// helper for fatal exception (windows only)
std::string fatalExceptionToString(const LogMessage& msg) {
std::string out; // clear any previous text and formatting
out.append("\n" + msg.timestamp() + "." + msg.microseconds()
out.append("\n" + msg.timestamp()
+ "\n\n***** FATAL EXCEPTION RECEIVED ******* \n"
+ '"' + msg.message() + '"');
return out;
Expand Down Expand Up @@ -122,7 +111,7 @@ namespace g3 {


std::string LogMessage::timestamp(const std::string& time_look) const {
return localtime_formatted(_timestamp, time_look);
return g3::localtime_formatted(_timestamp, time_look);
}


Expand All @@ -136,14 +125,17 @@ namespace g3 {

LogMessage::LogMessage(const std::string& file, const int line,
const std::string& function, const LEVELS& level)
: _timestamp(g3::systemtime_now())
, _call_thread_id(std::this_thread::get_id())
, _microseconds(microsecondsCounter())
: _call_thread_id(std::this_thread::get_id())
, _file(splitFileName(file))
, _line(line)
, _function(function)
, _level(level)
{}
{
g3::timespec_get(&_timestamp/*, TIME_UTC*/);
// Another possibility could be to Falling back to clock_gettime as TIME_UTC
// is not recognized by travis CI.
// i.e. clock_gettime(CLOCK_REALTIME, &_timestamp);
}


LogMessage::LogMessage(const std::string& fatalOsSignalCrashMessage)
Expand All @@ -154,7 +146,6 @@ namespace g3 {
LogMessage::LogMessage(const LogMessage& other)
: _timestamp(other._timestamp)
, _call_thread_id(other._call_thread_id)
, _microseconds(other._microseconds)
, _file(other._file)
, _line(other._line)
, _function(other._function)
Expand All @@ -166,7 +157,6 @@ namespace g3 {
LogMessage::LogMessage(LogMessage &&other)
: _timestamp(other._timestamp)
, _call_thread_id(other._call_thread_id)
, _microseconds(other._microseconds)
, _file(std::move(other._file))
, _line(other._line)
, _function(std::move(other._function))
Expand All @@ -183,6 +173,8 @@ namespace g3 {
return oss.str();
}



FatalMessage::FatalMessage(const LogMessage& details, g3::SignalType signal_id)
: LogMessage(details), _signal_id(signal_id) { }

Expand Down
111 changes: 101 additions & 10 deletions src/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,53 @@
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/

#include "g3log/time.hpp"

#include <sstream>
#include <string>
#include <cstring>
#include <cmath>
#include <chrono>
#include <cassert>
#include <iomanip>
#ifdef __MACH__
#include <sys/time.h>
#endif


namespace {
const size_t kMsDigitsToCut = 1000000; // 3 digits left of 1000 000 000
const size_t kUsDigitsToCut = 1000; // 6 digits left
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think about the naming + what is needed to be here and what can be defined static namespace or in the function?

const size_t kNsDigitsToCut = 1; // all digits left : divide by 1
const size_t kNsDefaultDigits = 0;
const size_t kDigitIdentifier = 1;
const size_t kNoDigitIdentifier = 0;

const std::string kIdentifier = "%f";
const size_t kIdentifierSize = 2;


std::string fractional_to_string(size_t fractional, size_t cutOffDivider) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has to be moved to the .h/cpp so that it can be put under test

auto zeroes = 9; // default ns
if (kMsDigitsToCut == cutOffDivider) {
zeroes = 3;
} else if (kUsDigitsToCut == cutOffDivider) {
zeroes = 6;
} else {
cutOffDivider = 1;
}
fractional /= cutOffDivider;

// auto value = std::to_string(typeAdjustedValue);
// return value; // std::string(fractional_digit, '0') + value;
auto value = std::string(std::to_string(fractional));
return std::string(zeroes - value.size(), '0') + value;
}
} // anonymous


namespace g3 {
Expand All @@ -21,21 +57,21 @@ namespace g3 {
// This is needed since latest version (at time of writing) of gcc4.7 does not implement this library function yet.
// return value is SIMPLIFIED to only return a std::string

std::string put_time(const struct tm *tmb, const char *c_time_format) {
std::string put_time(const struct tm* tmb, const char* c_time_format) {
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__MINGW32__)
std::ostringstream oss;
oss.fill('0');
// BOGUS hack done for VS2012: C++11 non-conformant since it SHOULD take a "const struct tm* "
oss << std::put_time(const_cast<struct tm *> (tmb), c_time_format);
oss << std::put_time(const_cast<struct tm*> (tmb), c_time_format);
return oss.str();
#else // LINUX
const size_t size = 1024;
char buffer[size]; // IMPORTANT: check now and then for when gcc will implement std::put_time.
// ... also ... This is way more buffer space then we need

auto success = std::strftime(buffer, size, c_time_format, tmb);
if (0 == success)
{
// TODO: incorrect code
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove erroneous comment

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider replacing the assert to something that will tricker process exit even for production code. The if 0 == success can then be removed also.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No code change but added a comment so that code readers that have not seen this pattern before will be less baffled by it. It is essentially a way of exiting with a clear message in debug mode. In production mode a safe value is instead returned.

if (0 == success) {
assert((0 != success) && "strftime fails with illegal formatting");
return c_time_format;
}
Expand All @@ -55,7 +91,33 @@ namespace g3 {
return std::chrono::system_clock::to_time_t(system_now);
}

tm localtime(const std::time_t &time) {

int timespec_get(struct timespec* ts/*, int base*/) {
#ifdef __MACH__
// std::timespec_get or posix clock_gettime)(...) are not
// implemented on OSX
// @return value of base if successful, else zero
struct timeval now = {};
int rv = gettimeofday(&now, nullptr);
if (-1 == rv) {
return rv;
}
// error mode. just return sec, microsecond
ts->tv_sec = now.tv_sec;
ts->tv_nsec = now.tv_usec * 1000;
return 0;
#else
// Linux
return std::timespec_get(ts, TIME_UTC));
#endif
}






tm localtime(const std::time_t& time) {
struct tm tm_snapshot;
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__))
localtime_s(&tm_snapshot, &time); // windsows
Expand All @@ -65,11 +127,40 @@ namespace g3 {
return tm_snapshot;
}

/// returns a std::string with content of time_t as localtime formatted by input format string
/// * format string must conform to std::put_time
/// This is similar to std::put_time(std::localtime(std::time_t*), time_format.c_str());

std::string localtime_formatted(const std::time_t &time_snapshot, const std::string &time_format) {

size_t fractional_cutoff(const std::string& format_buffer, size_t pos) {
char ch = (format_buffer.size() > pos + kIdentifierSize ? format_buffer.at(pos + kIdentifierSize) : '\0');
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make testable

size_t cutOff = 0;
switch (ch) {
case '3': cutOff = kMsDigitsToCut; break;
case '6': cutOff = kUsDigitsToCut; break;
case '9': cutOff = kNsDigitsToCut; break;
default: cutOff = kNsDefaultDigits; break;
Copy link
Owner Author

@KjellKod KjellKod Jul 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider instead Fractional::ns/ns_default/us/ms

}
return cutOff;
}


std::string localtime_formatted(const timespec& time_snapshot, const std::string& time_format) {
auto format_buffer = time_format; // copying format string to a separate buffer

// iterating through every "%f" instance in the format string
auto identifierExtraSize = 0;
for (size_t pos = 0; (pos = format_buffer.find(kIdentifier, pos)) != std::string::npos; pos += kIdentifierSize + identifierExtraSize) {
// figuring out whether this is nano, micro or milli identifier
auto cutoff = fractional_cutoff(format_buffer, pos);
auto value = fractional_to_string(time_snapshot.tv_nsec, cutoff);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider having the function which makes more sense
g3::fractional_to_string(time_snapshot /*i.e. it takes the timespec*/, FractionalType::us/ms/ns);
it's just way more readable than the 1000000000, 1000000, 1000 and with one if-else switch all the nastiness is dealt with

auto identifierExtraSize = cutoff == kNsDefaultDigits ? kNoDigitIdentifier : kDigitIdentifier;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go through naming


// replacing "%f[3|6|9]" with sec fractional part value
format_buffer.replace(pos, kIdentifier.size() + identifierExtraSize, value);
}

return localtime_formatted(time_snapshot.tv_sec, format_buffer);
}

std::string localtime_formatted(const std::time_t& time_snapshot, const std::string& time_format) {
std::tm t = localtime(time_snapshot); // could be const, but cannot due to VS2012 is non conformant for C++11's std::put_time (see above)
return g3::internal::put_time(&t, time_format.c_str()); // format example: //"%Y/%m/%d %H:%M:%S");
}
Expand Down