Commit cb755695 authored by gabime's avatar gabime

Fixed issue #266 (Improperly-formatted ISO8601 UTC offset for negative-offset timezones)

parent bf327be7
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
#pragma once #pragma once
#include <spdlog/formatter.h> #include <spdlog/formatter.h>
#include <spdlog/details/log_msg.h> #include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h> #include <spdlog/details/os.h>
#include <spdlog/fmt/fmt.h> #include <spdlog/fmt/fmt.h>
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
class flag_formatter class flag_formatter
{ {
public: public:
virtual ~flag_formatter() virtual ~flag_formatter()
{} {}
virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0; virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0;
}; };
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// name & level pattern appenders // name & level pattern appenders
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
namespace namespace
{ {
class name_formatter:public flag_formatter class name_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm&) override void format(details::log_msg& msg, const std::tm&) override
{ {
msg.formatted << *msg.logger_name; msg.formatted << *msg.logger_name;
} }
}; };
} }
// log level appender // log level appender
class level_formatter:public flag_formatter class level_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm&) override void format(details::log_msg& msg, const std::tm&) override
{ {
msg.formatted << level::to_str(msg.level); msg.formatted << level::to_str(msg.level);
} }
}; };
// short log level appender // short log level appender
class short_level_formatter:public flag_formatter class short_level_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm&) override void format(details::log_msg& msg, const std::tm&) override
{ {
msg.formatted << level::to_short_str(msg.level); msg.formatted << level::to_short_str(msg.level);
} }
}; };
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// Date time pattern appenders // Date time pattern appenders
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
static const char* ampm(const tm& t) static const char* ampm(const tm& t)
{ {
return t.tm_hour >= 12 ? "PM" : "AM"; return t.tm_hour >= 12 ? "PM" : "AM";
} }
static int to12h(const tm& t) static int to12h(const tm& t)
{ {
return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
} }
//Abbreviated weekday name //Abbreviated weekday name
static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
class a_formatter:public flag_formatter class a_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << days[tm_time.tm_wday]; msg.formatted << days[tm_time.tm_wday];
} }
}; };
//Full weekday name //Full weekday name
static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
class A_formatter:public flag_formatter class A_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << full_days[tm_time.tm_wday]; msg.formatted << full_days[tm_time.tm_wday];
} }
}; };
//Abbreviated month //Abbreviated month
static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" }; static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
class b_formatter:public flag_formatter class b_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << months[tm_time.tm_mon]; msg.formatted << months[tm_time.tm_mon];
} }
}; };
//Full month name //Full month name
static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
class B_formatter:public flag_formatter class B_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << full_months[tm_time.tm_mon]; msg.formatted << full_months[tm_time.tm_mon];
} }
}; };
//write 2 ints seperated by sep with padding of 2 //write 2 ints seperated by sep with padding of 2
static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep) static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep)
{ {
w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0'); w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0');
return w; return w;
} }
//write 3 ints seperated by sep with padding of 2 //write 3 ints seperated by sep with padding of 2
static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep) static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep)
{ {
w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0'); w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0');
return w; return w;
} }
//Date and time representation (Thu Aug 23 15:35:46 2014) //Date and time representation (Thu Aug 23 15:35:46 2014)
class c_formatter:public flag_formatter class c_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;
} }
}; };
// year - 2 digit // year - 2 digit
class C_formatter:public flag_formatter class C_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0'); msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0');
} }
}; };
// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
class D_formatter:public flag_formatter class D_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/'); pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/');
} }
}; };
// year - 4 digit // year - 4 digit
class Y_formatter:public flag_formatter class Y_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << tm_time.tm_year + 1900; msg.formatted << tm_time.tm_year + 1900;
} }
}; };
// month 1-12 // month 1-12
class m_formatter:public flag_formatter class m_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0'); msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0');
} }
}; };
// day of month 1-31 // day of month 1-31
class d_formatter:public flag_formatter class d_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0'); msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0');
} }
}; };
// hours in 24 format 0-23 // hours in 24 format 0-23
class H_formatter:public flag_formatter class H_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0'); msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0');
} }
}; };
// hours in 12 format 1-12 // hours in 12 format 1-12
class I_formatter:public flag_formatter class I_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(to12h(tm_time), 2, '0'); msg.formatted << fmt::pad(to12h(tm_time), 2, '0');
} }
}; };
// minutes 0-59 // minutes 0-59
class M_formatter:public flag_formatter class M_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(tm_time.tm_min, 2, '0'); msg.formatted << fmt::pad(tm_time.tm_min, 2, '0');
} }
}; };
// seconds 0-59 // seconds 0-59
class S_formatter:public flag_formatter class S_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0'); msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0');
} }
}; };
// milliseconds // milliseconds
class e_formatter:public flag_formatter class e_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm&) override void format(details::log_msg& msg, const std::tm&) override
{ {
auto duration = msg.time.time_since_epoch(); auto duration = msg.time.time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000; auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0'); msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0');
} }
}; };
// microseconds // microseconds
class f_formatter:public flag_formatter class f_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm&) override void format(details::log_msg& msg, const std::tm&) override
{ {
auto duration = msg.time.time_since_epoch(); auto duration = msg.time.time_since_epoch();
auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000; auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000;
msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0'); msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0');
} }
}; };
// nanoseconds // nanoseconds
class F_formatter:public flag_formatter class F_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm&) override void format(details::log_msg& msg, const std::tm&) override
{ {
auto duration = msg.time.time_since_epoch(); auto duration = msg.time.time_since_epoch();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 1000000000; auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 1000000000;
msg.formatted << fmt::pad(static_cast<int>(ns), 9, '0'); msg.formatted << fmt::pad(static_cast<int>(ns), 9, '0');
} }
}; };
// AM/PM // AM/PM
class p_formatter:public flag_formatter class p_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
msg.formatted << ampm(tm_time); msg.formatted << ampm(tm_time);
} }
}; };
// 12 hour clock 02:55:02 pm // 12 hour clock 02:55:02 pm
class r_formatter:public flag_formatter class r_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time); pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time);
} }
}; };
// 24-hour HH:MM time, equivalent to %H:%M // 24-hour HH:MM time, equivalent to %H:%M
class R_formatter:public flag_formatter class R_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':'); pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':');
} }
}; };
// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
class T_formatter:public flag_formatter class T_formatter:public flag_formatter
{ {
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':'); pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':');
} }
}; };
// ISO 8601 offset from UTC in timezone (+-HH:MM) // ISO 8601 offset from UTC in timezone (+-HH:MM)
class z_formatter:public flag_formatter class z_formatter:public flag_formatter
{ {
public: public:
const std::chrono::seconds cache_refresh = std::chrono::seconds(5); const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
z_formatter():_last_update(std::chrono::seconds(0)) z_formatter():_last_update(std::chrono::seconds(0))
{} {}
z_formatter(const z_formatter&) = delete; z_formatter(const z_formatter&) = delete;
z_formatter& operator=(const z_formatter&) = delete; z_formatter& operator=(const z_formatter&) = delete;
void format(details::log_msg& msg, const std::tm& tm_time) override void format(details::log_msg& msg, const std::tm& tm_time) override
{ {
#ifdef _WIN32 #ifdef _WIN32
int total_minutes = get_cached_offset(msg, tm_time); int total_minutes = get_cached_offset(msg, tm_time);
#else #else
// No need to chache under gcc, // No need to chache under gcc,
// it is very fast (already stored in tm.tm_gmtoff) // it is very fast (already stored in tm.tm_gmtoff)
int total_minutes = os::utc_minutes_offset(tm_time); int total_minutes = os::utc_minutes_offset(tm_time);
#endif #endif
bool is_negative = total_minutes < 0;
int h = total_minutes / 60; char sign;
int m = total_minutes % 60; if (is_negative)
if (h >= 0) //minus sign will be printed anyway if negative {
{ total_minutes = -total_minutes;
msg.formatted << '+'; sign = '-';
} }
pad_n_join(msg.formatted, h, m, ':'); else
} {
private: sign = '+';
log_clock::time_point _last_update; }
int _offset_minutes;
std::mutex _mutex; int h = total_minutes / 60;
int m = total_minutes % 60;
int get_cached_offset(const log_msg& msg, const std::tm& tm_time) msg.formatted << sign;
{ pad_n_join(msg.formatted, h, m, ':');
using namespace std::chrono; }
std::lock_guard<std::mutex> l(_mutex); private:
if (msg.time - _last_update >= cache_refresh) log_clock::time_point _last_update;
{ int _offset_minutes;
_offset_minutes = os::utc_minutes_offset(tm_time); std::mutex _mutex;
_last_update = msg.time;
} int get_cached_offset(const log_msg& msg, const std::tm& tm_time)
return _offset_minutes; {
} using namespace std::chrono;
}; std::lock_guard<std::mutex> l(_mutex);
if (msg.time - _last_update >= cache_refresh)
{
_offset_minutes = os::utc_minutes_offset(tm_time);
//Thread id _last_update = msg.time;
class t_formatter:public flag_formatter }
{ return _offset_minutes;
void format(details::log_msg& msg, const std::tm&) override }
{ };
msg.formatted << msg.thread_id;
}
};
//Thread id
class t_formatter:public flag_formatter
class v_formatter:public flag_formatter {
{ void format(details::log_msg& msg, const std::tm&) override
void format(details::log_msg& msg, const std::tm&) override {
{ msg.formatted << msg.thread_id;
msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); }
} };
};
class ch_formatter:public flag_formatter class v_formatter:public flag_formatter
{ {
public: void format(details::log_msg& msg, const std::tm&) override
explicit ch_formatter(char ch): _ch(ch) {
{} msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
void format(details::log_msg& msg, const std::tm&) override }
{ };
msg.formatted << _ch;
} class ch_formatter:public flag_formatter
private: {
char _ch; public:
}; explicit ch_formatter(char ch): _ch(ch)
{}
void format(details::log_msg& msg, const std::tm&) override
//aggregate user chars to display as is {
class aggregate_formatter:public flag_formatter msg.formatted << _ch;
{ }
public: private:
aggregate_formatter() char _ch;
{} };
void add_ch(char ch)
{
_str += ch; //aggregate user chars to display as is
} class aggregate_formatter:public flag_formatter
void format(details::log_msg& msg, const std::tm&) override {
{ public:
msg.formatted << _str; aggregate_formatter()
} {}
private: void add_ch(char ch)
std::string _str; {
}; _str += ch;
}
// Full info formatter void format(details::log_msg& msg, const std::tm&) override
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v {
class full_formatter:public flag_formatter msg.formatted << _str;
{ }
void format(details::log_msg& msg, const std::tm& tm_time) override private:
{ std::string _str;
#ifndef SPDLOG_NO_DATETIME };
auto duration = msg.time.time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000; // Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
/* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), class full_formatter:public flag_formatter
msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", {
tm_time.tm_year + 1900, void format(details::log_msg& msg, const std::tm& tm_time) override
tm_time.tm_mon + 1, {
tm_time.tm_mday, #ifndef SPDLOG_NO_DATETIME
tm_time.tm_hour, auto duration = msg.time.time_since_epoch();
tm_time.tm_min, auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
tm_time.tm_sec,
static_cast<int>(millis), /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),
msg.logger_name, msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ",
level::to_str(msg.level), tm_time.tm_year + 1900,
msg.raw.str());*/ tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) tm_time.tm_min,
msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-' tm_time.tm_sec,
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-' static_cast<int>(millis),
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' ' msg.logger_name,
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':' level::to_str(msg.level),
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':' msg.raw.str());*/
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.'
<< fmt::pad(static_cast<unsigned int>(millis), 3, '0') << "] ";
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
//no datetime needed msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-'
#else << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-'
(void)tm_time; << fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' '
#endif << fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':'
<< fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':'
#ifndef SPDLOG_NO_NAME << fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.'
msg.formatted << '[' << *msg.logger_name << "] "; << fmt::pad(static_cast<unsigned int>(millis), 3, '0') << "] ";
#endif
//no datetime needed
msg.formatted << '[' << level::to_str(msg.level) << "] "; #else
msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); (void)tm_time;
} #endif
};
#ifndef SPDLOG_NO_NAME
} msg.formatted << '[' << *msg.logger_name << "] ";
} #endif
///////////////////////////////////////////////////////////////////////////////
// pattern_formatter inline impl msg.formatted << '[' << level::to_str(msg.level) << "] ";
/////////////////////////////////////////////////////////////////////////////// msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern) }
{ };
compile_pattern(pattern);
} }
}
inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern) ///////////////////////////////////////////////////////////////////////////////
{ // pattern_formatter inline impl
auto end = pattern.end(); ///////////////////////////////////////////////////////////////////////////////
std::unique_ptr<details::aggregate_formatter> user_chars; inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern)
for (auto it = pattern.begin(); it != end; ++it) {
{ compile_pattern(pattern);
if (*it == '%') }
{
if (user_chars) //append user chars found so far inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
_formatters.push_back(std::move(user_chars)); {
auto end = pattern.end();
if (++it != end) std::unique_ptr<details::aggregate_formatter> user_chars;
handle_flag(*it); for (auto it = pattern.begin(); it != end; ++it)
else {
break; if (*it == '%')
} {
else // chars not following the % sign should be displayed as is if (user_chars) //append user chars found so far
{ _formatters.push_back(std::move(user_chars));
if (!user_chars)
user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter()); if (++it != end)
user_chars->add_ch(*it); handle_flag(*it);
} else
} break;
if (user_chars) //append raw chars found so far }
{ else // chars not following the % sign should be displayed as is
_formatters.push_back(std::move(user_chars)); {
} if (!user_chars)
user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());
} user_chars->add_ch(*it);
inline void spdlog::pattern_formatter::handle_flag(char flag) }
{ }
switch (flag) if (user_chars) //append raw chars found so far
{ {
// logger name _formatters.push_back(std::move(user_chars));
case 'n': }
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter()));
break; }
inline void spdlog::pattern_formatter::handle_flag(char flag)
case 'l': {
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::level_formatter())); switch (flag)
break; {
// logger name
case 'L': case 'n':
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::short_level_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter()));
break; break;
case('t'): case 'l':
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::t_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::level_formatter()));
break; break;
case('v'): case 'L':
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::v_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::short_level_formatter()));
break; break;
case('a'): case('t'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::a_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::t_formatter()));
break; break;
case('A'): case('v'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::A_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::v_formatter()));
break; break;
case('b'): case('a'):
case('h'): _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::a_formatter()));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::b_formatter())); break;
break;
case('A'):
case('B'): _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::A_formatter()));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::B_formatter())); break;
break;
case('c'): case('b'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::c_formatter())); case('h'):
break; _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::b_formatter()));
break;
case('C'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::C_formatter())); case('B'):
break; _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::B_formatter()));
break;
case('Y'): case('c'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::Y_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::c_formatter()));
break; break;
case('D'): case('C'):
case('x'): _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::C_formatter()));
break;
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::D_formatter()));
break; case('Y'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::Y_formatter()));
case('m'): break;
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::m_formatter()));
break; case('D'):
case('x'):
case('d'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::d_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::D_formatter()));
break; break;
case('H'): case('m'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::H_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::m_formatter()));
break; break;
case('I'): case('d'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::I_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::d_formatter()));
break; break;
case('M'): case('H'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::M_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::H_formatter()));
break; break;
case('S'): case('I'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::S_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::I_formatter()));
break; break;
case('e'): case('M'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::e_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::M_formatter()));
break; break;
case('f'): case('S'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::f_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::S_formatter()));
break; break;
case('F'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::F_formatter())); case('e'):
break; _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::e_formatter()));
break;
case('p'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::p_formatter())); case('f'):
break; _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::f_formatter()));
break;
case('r'): case('F'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::r_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::F_formatter()));
break; break;
case('R'): case('p'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::R_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::p_formatter()));
break; break;
case('T'): case('r'):
case('X'): _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::r_formatter()));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::T_formatter())); break;
break;
case('R'):
case('z'): _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::R_formatter()));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::z_formatter())); break;
break;
case('T'):
case ('+'): case('X'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::T_formatter()));
break; break;
default: //Unkown flag appears as is case('z'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%'))); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::z_formatter()));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag))); break;
break;
} case ('+'):
} _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter()));
break;
inline void spdlog::pattern_formatter::format(details::log_msg& msg) default: //Unkown flag appears as is
{ _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%')));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag)));
#ifndef SPDLOG_NO_DATETIME break;
auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); }
#else }
std::tm tm_time;
#endif
for (auto &f : _formatters) inline void spdlog::pattern_formatter::format(details::log_msg& msg)
{ {
f->format(msg, tm_time);
} #ifndef SPDLOG_NO_DATETIME
//write eol auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time));
msg.formatted.write(details::os::eol, details::os::eol_size); #else
} std::tm tm_time;
#endif
for (auto &f : _formatters)
{
f->format(msg, tm_time);
}
//write eol
msg.formatted.write(details::os::eol, details::os::eol_size);
}
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