Commit 7a17ff02 authored by captainwong's avatar captainwong

basic log

parent bfb60af5
...@@ -3,14 +3,13 @@ ...@@ -3,14 +3,13 @@
#include "config.h" #include "config.h"
#include "logstream.h" #include "logstream.h"
#include "timestamp.h" #include "timestamp.h"
#include "timezone.h"
#include "currentthread.h" #include "currentthread.h"
#include <stdlib.h> // getenv #include <stdlib.h> // getenv
namespace jlib namespace jlib
{ {
class TimeZone;
class Logger class Logger
{ {
public: public:
...@@ -29,13 +28,21 @@ public: ...@@ -29,13 +28,21 @@ public:
{ {
template <int N> template <int N>
SourceFile(const char(&arr)[N]) : data_(arr), size_(N - 1) { SourceFile(const char(&arr)[N]) : data_(arr), size_(N - 1) {
#ifdef JLIB_WINDOWS
const char* slash = strrchr(data_, '\\');
#else
const char* slash = strrchr(data_, '/'); const char* slash = strrchr(data_, '/');
#endif
if (slash) { data_ = slash + 1; } if (slash) { data_ = slash + 1; }
size_ -= static_cast<int>(data_ - arr); size_ -= static_cast<int>(data_ - arr);
} }
explicit SourceFile(const char* filename) : data_(filename) { 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; } if (slash) { data_ = slash + 1; }
size_ = static_cast<int>(strlen(data_)); size_ = static_cast<int>(strlen(data_));
} }
...@@ -44,19 +51,29 @@ public: ...@@ -44,19 +51,29 @@ public:
int size_; int size_;
}; };
Logger(SourceFile file, int line); Logger(SourceFile file, int line) : impl_(LogLevel::LOGLEVEL_INFO, 0, file, line) {}
Logger(SourceFile file, int line, LogLevel level); Logger(SourceFile file, int line, LogLevel level) : impl_(level, 0, file, line) {}
Logger(SourceFile file, int line, LogLevel level, const char* func); 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); Logger(SourceFile file, int line, bool toAbort) : impl_(toAbort ? LogLevel::LOGLEVEL_FATAL : LOGLEVEL_ERROR, errno, file, line) {}
~Logger();
~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_; } LogStream& stream() { return impl_.stream_; }
static LogLevel logLevel() { return logLevel_; } 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 (*OutputFunc)(const char* msg, int len);
typedef void (*FlushFunc)(); typedef void (*FlushFunc)();
static void setOutput(OutputFunc); static void setOutput(OutputFunc);
static void setFlush(FlushFunc); static void setFlush(FlushFunc);
static void setTimeZone(const TimeZone& tz); static void setTimeZone(const TimeZone& tz);
...@@ -79,24 +96,41 @@ private: ...@@ -79,24 +96,41 @@ private:
SourceFile basename_; SourceFile basename_;
}; };
static OutputFunc outputFunc_;
static FlushFunc flushFunc_;
static LogLevel logLevel_; static LogLevel logLevel_;
static TimeZone timeZone_;
Impl impl_; Impl impl_;
}; };
static void defaultOutput(const char* msg, int len) { fwrite(msg, 1, len, stdout); } /******** log micros *********/
static void defaultFlush() { fflush(stdout); }
static Logger::OutputFunc g_output = defaultOutput; #define LOG_TRACE if (jlib::Logger::logLevel() <= jlib::Logger::LogLevel::LOGLEVEL_TRACE) \
static Logger::FlushFunc g_flush = defaultFlush; 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 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 ", "TRACE ",
"DEBUG ", "DEBUG ",
"INFO ", "INFO ",
...@@ -131,11 +165,20 @@ struct T ...@@ -131,11 +165,20 @@ struct T
thread_local char t_errnobuf[512] = { 0 }; thread_local char t_errnobuf[512] = { 0 };
thread_local char t_time[64] = { 0 }; thread_local char t_time[64] = { 0 };
thread_local time_t t_lastSecond = 0; thread_local time_t t_lastSecond = 0;
static constexpr unsigned int T_TIME_STR_LEN = 17;
} // detail } // detail
/******** static initializer *********/
Logger::OutputFunc Logger::outputFunc_ = detail::defaultOutput;
Logger::FlushFunc Logger::flushFunc_ = detail::defaultFlush;
Logger::LogLevel Logger::logLevel_ = detail::initLogLevel(); Logger::LogLevel Logger::logLevel_ = detail::initLogLevel();
TimeZone Logger::timeZone_ = {};
/******** LogStream operators *********/
inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& f) { inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& f) {
s.append(f.data_, f.size_); return s; s.append(f.data_, f.size_); return s;
...@@ -151,6 +194,8 @@ static const char* strerror_t(int savedErrno) { ...@@ -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) Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int line)
: time_(Timestamp::now()) : time_(Timestamp::now())
, stream_() , stream_()
...@@ -170,12 +215,34 @@ Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int li ...@@ -170,12 +215,34 @@ Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int li
void Logger::Impl::formatTime() void Logger::Impl::formatTime()
{ {
int64_t microSecsSinceEpoch = time_.microSecondsSinceEpoch(); int64_t microSecsSinceEpoch = time_.microSecondsSinceEpoch();
time_t seconds = static_cast<time_t>(microSecsSinceEpoch / Timestamp::MICRO_SECONDS_PER_SECOND); time_t seconds = static_cast<time_t>(microSecsSinceEpoch / MICRO_SECONDS_PER_SECOND);
int microsecs = static_cast<int>(microSecsSinceEpoch % Timestamp::MICRO_SECONDS_PER_SECOND); int microsecs = static_cast<int>(microSecsSinceEpoch % MICRO_SECONDS_PER_SECOND);
if (seconds != detail::t_lastSecond) { if (seconds != detail::t_lastSecond) {
detail::t_lastSecond = seconds; 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';
} }
......
...@@ -346,14 +346,15 @@ static std::string formatSI(int64_t s) ...@@ -346,14 +346,15 @@ static std::string formatSI(int64_t s)
*/ */
static std::string formatIEC(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); double n = static_cast<double>(s);
char buf[64]; 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) if (n < Ki)
snprintf(buf, sizeof buf, "%" PRId64, s); snprintf(buf, sizeof buf, "%" PRId64, s);
......
...@@ -71,46 +71,46 @@ struct LocalTime ...@@ -71,46 +71,46 @@ struct LocalTime
static constexpr int SECONDS_PER_DAY = 24 * 60 * 60; static constexpr int SECONDS_PER_DAY = 24 * 60 * 60;
//! TimeZone for 1970~2030 //! TimeZone for 1970~2030
class Timezone : public copyable class TimeZone : public copyable
{ {
public: 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{ bool valid() const{
return static_cast<bool>(data_); 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 struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false);
static time_t fromUtcTime(const struct tm& tm_time); //static time_t fromUtcTime(const struct tm& tm_time);
//
/** ///**
* @param year [1900, 2500] //* @param year [1900, 2500]
* @param month [1, 12] //* @param month [1, 12]
* @param day [1, 31] //* @param day [1, 31]
* @param hour [0, 23] //* @param hour [0, 23]
* @param minute [0, 59] //* @param minute [0, 59]
* @param seconds [0, 59] //* @param seconds [0, 59]
*/ //*/
static time_t fromUtcTime(int year, int month, int day, //static time_t fromUtcTime(int year, int month, int day,
int hour, int minute, int seconds) { // int hour, int minute, int seconds) {
} //}
struct Data { struct Data {
std::vector<detail::Transition> transitions; std::vector<detail::Transition> transitions;
......
#include "../../jlib/base/logging.h" #include "../../jlib/base/logging.h"
using namespace jlib;
int main() 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
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(BOOST);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment