From 7a17ff02113664e466ba8cd35e6d2ae0049f0bc9 Mon Sep 17 00:00:00 2001 From: i7-8700 <1281261856@qq.com> Date: Mon, 23 Sep 2019 22:44:27 +0800 Subject: [PATCH] basic log --- jlib/base/logging.h | 101 ++++++++++++++++++++----- jlib/base/logstream.h | 13 ++-- jlib/base/timezone.h | 44 +++++------ test/test_logging/test_logging.cpp | 12 +++ test/test_logging/test_logging.vcxproj | 1 + 5 files changed, 126 insertions(+), 45 deletions(-) diff --git a/jlib/base/logging.h b/jlib/base/logging.h index d3d6d5b..de1a46d 100644 --- a/jlib/base/logging.h +++ b/jlib/base/logging.h @@ -3,14 +3,13 @@ #include "config.h" #include "logstream.h" #include "timestamp.h" +#include "timezone.h" #include "currentthread.h" #include <stdlib.h> // getenv namespace jlib { -class TimeZone; - class Logger { public: @@ -29,13 +28,21 @@ public: { template <int N> SourceFile(const char(&arr)[N]) : data_(arr), size_(N - 1) { +#ifdef JLIB_WINDOWS + const char* slash = strrchr(data_, '\\'); +#else const char* slash = strrchr(data_, '/'); +#endif if (slash) { data_ = slash + 1; } size_ -= static_cast<int>(data_ - arr); } explicit SourceFile(const char* filename) : data_(filename) { - const char* slash = strrchr(filename, '/'); +#ifdef JLIB_WINDOWS + const char* slash = strrchr(data_, '\\'); +#else + const char* slash = strrchr(data_, '/'); +#endif if (slash) { data_ = slash + 1; } size_ = static_cast<int>(strlen(data_)); } @@ -44,19 +51,29 @@ public: int size_; }; - Logger(SourceFile file, int line); - Logger(SourceFile file, int line, LogLevel level); - Logger(SourceFile file, int line, LogLevel level, const char* func); - Logger(SourceFile file, int line, bool toAbort); - ~Logger(); + Logger(SourceFile file, int line) : impl_(LogLevel::LOGLEVEL_INFO, 0, file, line) {} + Logger(SourceFile file, int line, LogLevel level) : impl_(level, 0, file, line) {} + Logger(SourceFile file, int line, LogLevel level, const char* func) : impl_(level, 0, file, line) { impl_.stream_ << func << ' '; } + Logger(SourceFile file, int line, bool toAbort) : impl_(toAbort ? LogLevel::LOGLEVEL_FATAL : LOGLEVEL_ERROR, errno, file, line) {} + + ~Logger() { + impl_.finish(); + const auto& buf = impl_.stream_.buffer(); + outputFunc_(buf.data(), buf.length()); + if (impl_.level_ == LOGLEVEL_FATAL) { + flushFunc_(); + abort(); + } + } LogStream& stream() { return impl_.stream_; } static LogLevel logLevel() { return logLevel_; } - static void setLogLevel(LogLevel level); + static void setLogLevel(LogLevel level) { logLevel_ = level; } typedef void (*OutputFunc)(const char* msg, int len); typedef void (*FlushFunc)(); + static void setOutput(OutputFunc); static void setFlush(FlushFunc); static void setTimeZone(const TimeZone& tz); @@ -79,24 +96,41 @@ private: SourceFile basename_; }; + static OutputFunc outputFunc_; + static FlushFunc flushFunc_; static LogLevel logLevel_; + static TimeZone timeZone_; Impl impl_; }; -static void defaultOutput(const char* msg, int len) { fwrite(msg, 1, len, stdout); } -static void defaultFlush() { fflush(stdout); } +/******** log micros *********/ -static Logger::OutputFunc g_output = defaultOutput; -static Logger::FlushFunc g_flush = defaultFlush; +#define LOG_TRACE if (jlib::Logger::logLevel() <= jlib::Logger::LogLevel::LOGLEVEL_TRACE) \ + jlib::Logger(__FILE__, __LINE__, jlib::Logger::LogLevel::LOGLEVEL_TRACE, __func__).stream() + +#define LOG_DEBUG if (jlib::Logger::logLevel() <= jlib::Logger::LogLevel::LOGLEVEL_DEBUG) \ + jlib::Logger(__FILE__, __LINE__, jlib::Logger::LogLevel::LOGLEVEL_DEBUG, __func__).stream() + +#define LOG_INFO if (jlib::Logger::logLevel() <= jlib::Logger::LogLevel::LOGLEVEL_INFO) \ + jlib::Logger(__FILE__, __LINE__, jlib::Logger::LogLevel::LOGLEVEL_INFO).stream() + + +#define LOG_WARN jlib::Logger(__FILE__, __LINE__, jlib::Logger::LogLevel::LOGLEVEL_WARN).stream() +#define LOG_ERROR jlib::Logger(__FILE__, __LINE__, jlib::Logger::LogLevel::LOGLEVEL_ERROR).stream() +#define LOG_FATAL jlib::Logger(__FILE__, __LINE__, jlib::Logger::LogLevel::LOGLEVEL_FATAL).stream() +#define LOG_SYSERR jlib::Logger(__FILE__, __LINE__, false).stream() +#define LOG_SYSFATAL jlib::Logger(__FILE__, __LINE__, true).stream() namespace detail { -static const char* LogLevelName[Logger::LogLevel::LOGLEVEL_COUNT] = -{ +static void defaultOutput(const char* msg, int len) { fwrite(msg, 1, len, stdout); } +static void defaultFlush() { fflush(stdout); } + +static const char* LogLevelName[Logger::LogLevel::LOGLEVEL_COUNT] = { "TRACE ", "DEBUG ", "INFO ", @@ -131,11 +165,20 @@ struct T thread_local char t_errnobuf[512] = { 0 }; thread_local char t_time[64] = { 0 }; thread_local time_t t_lastSecond = 0; +static constexpr unsigned int T_TIME_STR_LEN = 17; } // detail +/******** static initializer *********/ + +Logger::OutputFunc Logger::outputFunc_ = detail::defaultOutput; +Logger::FlushFunc Logger::flushFunc_ = detail::defaultFlush; Logger::LogLevel Logger::logLevel_ = detail::initLogLevel(); +TimeZone Logger::timeZone_ = {}; + + +/******** LogStream operators *********/ inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& f) { s.append(f.data_, f.size_); return s; @@ -151,6 +194,8 @@ static const char* strerror_t(int savedErrno) { } +/******** Logger::Impl *********/ + Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int line) : time_(Timestamp::now()) , stream_() @@ -170,12 +215,34 @@ Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int li void Logger::Impl::formatTime() { int64_t microSecsSinceEpoch = time_.microSecondsSinceEpoch(); - time_t seconds = static_cast<time_t>(microSecsSinceEpoch / Timestamp::MICRO_SECONDS_PER_SECOND); - int microsecs = static_cast<int>(microSecsSinceEpoch % Timestamp::MICRO_SECONDS_PER_SECOND); + time_t seconds = static_cast<time_t>(microSecsSinceEpoch / MICRO_SECONDS_PER_SECOND); + int microsecs = static_cast<int>(microSecsSinceEpoch % MICRO_SECONDS_PER_SECOND); if (seconds != detail::t_lastSecond) { detail::t_lastSecond = seconds; + struct tm tm_time; + if (timeZone_.valid()) { + // TODO + } else { + gmtime_r(&seconds, &tm_time); + } + int len = snprintf(detail::t_time, sizeof(detail::t_time), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + assert(len == detail::T_TIME_STR_LEN); (void)len; } + + if (timeZone_.valid()) { + // TODO + } else { + Format us(".%06dZ ", microsecs); assert(us.length() == 9); + stream_ << detail::T(detail::t_time, detail::T_TIME_STR_LEN) << detail::T(us.data(), 9); + } +} + +void Logger::Impl::finish() +{ + stream_ << " - " << basename_ << ':' << line_ << '\n'; } diff --git a/jlib/base/logstream.h b/jlib/base/logstream.h index 6946d9c..2837d0f 100644 --- a/jlib/base/logstream.h +++ b/jlib/base/logstream.h @@ -346,14 +346,15 @@ static std::string formatSI(int64_t s) */ static std::string formatIEC(int64_t s) { + static constexpr double Ki = 1024.0; + static constexpr double Mi = Ki * 1024.0; + static constexpr double Gi = Mi * 1024.0; + static constexpr double Ti = Gi * 1024.0; + static constexpr double Pi = Ti * 1024.0; + static constexpr double Ei = Pi * 1024.0; + double n = static_cast<double>(s); char buf[64]; - const double Ki = 1024.0; - const double Mi = Ki * 1024.0; - const double Gi = Mi * 1024.0; - const double Ti = Gi * 1024.0; - const double Pi = Ti * 1024.0; - const double Ei = Pi * 1024.0; if (n < Ki) snprintf(buf, sizeof buf, "%" PRId64, s); diff --git a/jlib/base/timezone.h b/jlib/base/timezone.h index 7bec454..b56ef70 100644 --- a/jlib/base/timezone.h +++ b/jlib/base/timezone.h @@ -71,46 +71,46 @@ struct LocalTime static constexpr int SECONDS_PER_DAY = 24 * 60 * 60; //! TimeZone for 1970~2030 -class Timezone : public copyable +class TimeZone : public copyable { public: - explicit Timezone(const char* zonename) { + explicit TimeZone(const char* zonename) { } - Timezone(int bias, const char* tzname) { + TimeZone(int bias, const char* tzname) { } - Timezone() = default; // invalid timezone + TimeZone() = default; // invalid timezone bool valid() const{ return static_cast<bool>(data_); } - struct tm toLocalTime(time_t secondsSinceEpoch) const { + //struct tm toLocalTime(time_t secondsSinceEpoch) const { - } + //} - time_t fromLocalTime(const struct tm& tm_time) const { + //time_t fromLocalTime(const struct tm& tm_time) const { - } + //} - static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); - static time_t fromUtcTime(const struct tm& tm_time); - - /** - * @param year [1900, 2500] - * @param month [1, 12] - * @param day [1, 31] - * @param hour [0, 23] - * @param minute [0, 59] - * @param seconds [0, 59] - */ - static time_t fromUtcTime(int year, int month, int day, - int hour, int minute, int seconds) { + //static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); + //static time_t fromUtcTime(const struct tm& tm_time); + // + ///** + //* @param year [1900, 2500] + //* @param month [1, 12] + //* @param day [1, 31] + //* @param hour [0, 23] + //* @param minute [0, 59] + //* @param seconds [0, 59] + //*/ + //static time_t fromUtcTime(int year, int month, int day, + // int hour, int minute, int seconds) { - } + //} struct Data { std::vector<detail::Transition> transitions; diff --git a/test/test_logging/test_logging.cpp b/test/test_logging/test_logging.cpp index 78a3a91..b3014d4 100644 --- a/test/test_logging/test_logging.cpp +++ b/test/test_logging/test_logging.cpp @@ -1,6 +1,18 @@ #include "../../jlib/base/logging.h" +using namespace jlib; + int main() { + Logger::setLogLevel(Logger::LOGLEVEL_TRACE); + LOG_TRACE << "trace"; + LOG_DEBUG << "debug"; + LOG_INFO << "Hello"; + LOG_WARN << "World"; + LOG_ERROR << "Error"; + LOG_INFO << sizeof(Logger); + LOG_INFO << sizeof(LogStream); + LOG_INFO << sizeof(Format); + LOG_INFO << sizeof(LogStream::Buffer); } \ No newline at end of file diff --git a/test/test_logging/test_logging.vcxproj b/test/test_logging/test_logging.vcxproj index 512b765..22693e6 100644 --- a/test/test_logging/test_logging.vcxproj +++ b/test/test_logging/test_logging.vcxproj @@ -88,6 +88,7 @@ <Optimization>Disabled</Optimization> <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(BOOST);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <SubSystem>Console</SubSystem> -- 2.18.1