@@ -37,76 +37,76 @@ limitations under the License.
3737#include < vector>
3838using namespace std ;
3939
40+ static uint32_t now0;
4041static struct tm alog_time = {0 };
4142
42- struct iovec_str : iovec {
43- template <size_t N>
44- constexpr iovec_str (const char (&s)[N])
45- : iovec{const_cast <char *>(s), N - 1 } {}
46- constexpr iovec_str (const char * s, size_t n)
47- : iovec{const_cast <char *>(s), n} {}
48- };
49-
50- constexpr static iovec_str alog_color_reset (" \033 [0m" );
51-
5243class BaseLogOutput : public ILogOutput {
5344public:
5445 uint64_t throttle = -1UL ;
5546 uint64_t count = 0 ;
56- time_t ts = 0 ;
47+ uint32_t ts = 0 ;
5748 int log_file_fd;
58- iovec_str level_prefix[ALOG_AUDIT + 1 ];
59-
60- constexpr BaseLogOutput (int fd = 0 )
61- : log_file_fd(fd),
62- level_prefix{ALOG_COLOR_DARKGRAY , ALOG_COLOR_LIGHTGRAY ,
63- ALOG_COLOR_YELLOW , ALOG_COLOR_RED ,
64- ALOG_COLOR_MAGENTA , ALOG_COLOR_CYAN ,
65- ALOG_COLOR_GREEN } {}
66-
67- void set_level_color (int level, const char * color, size_t len) override {
68- if (level < 0 || level > ALOG_AUDIT ) return ;
69- level_prefix[level] = {color, len};
49+ constexpr BaseLogOutput (int fd = 0 ) : log_file_fd(fd) { }
50+ unsigned char level_color[ALOG_AUDIT + 1 ] = { ALOG_COLOR_DARKGRAY ,
51+ ALOG_COLOR_NOTHING , ALOG_COLOR_YELLOW , ALOG_COLOR_RED ,
52+ ALOG_COLOR_MAGENTA , ALOG_COLOR_CYAN , ALOG_COLOR_GREEN };
53+ void clear_color () { memset (level_color, 0 , sizeof (level_color)); }
54+ uint16_t decode (uint16_t c) {
55+ c = ((c & 0xf ) << 8 ) | (c >> 4 );
56+ return c + *(uint16_t *)" 00" ;
57+ }
58+ uint16_t get_color (unsigned int level) {
59+ if (level < LEN (level_color))
60+ if (auto c = level_color[level])
61+ return decode (c);
62+ return 0 ;
63+ }
64+ int set_level_color (int level, unsigned char code) override {
65+ if ((uint32_t )level > ALOG_AUDIT )
66+ LOG_ERROR_RETURN (EINVAL , -1 , " invalid level " , level);
67+ auto dx = decode (code);
68+ if ((dx < decode (ALOG_COLOR_RED ) &&
69+ (dx > ALOG_COLOR_NOTHING )) ||
70+ (dx > decode (ALOG_COLOR_LIGHTWHITE )) ||
71+ (dx > decode (ALOG_COLOR_LIGHTGRAY ) &&
72+ (dx < decode (ALOG_COLOR_DARKGRAY )))) {
73+ LOG_ERROR_RETURN (EINVAL , -1 , " invalid color code " , code);
74+ }
75+ level_color[level] = code;
76+ return 0 ;
7077 }
7178
7279 struct LineIOV {
7380 struct iovec iov[3 ];
7481 size_t total_length;
7582 uint8_t iovst, iovcnt;
83+ char color_prefix[6 ] = " \033 [00m" ;
84+ LineIOV (uint16_t color, const char * begin, const char * end) {
85+ total_length = end - begin;
86+ iov[1 ] = {(void *)begin, total_length};
87+ if (!color) {
88+ iovst = iovcnt = 1 ;
89+ } else {
90+ *(uint16_t *)&color_prefix[2 ] = color;
91+ iov[0 ] = {color_prefix, LEN (color_prefix) - 1 };
92+ constexpr static char color_suffix[] = " \033 [0m" ;
93+ iov[2 ] = {(void *)color_suffix, LEN (color_suffix) - 1 };
94+ total_length += iov[0 ].iov_len + iov[2 ].iov_len ;
95+ iovst = 0 ; iovcnt = 3 ;
96+ }
97+ }
7698 iovec* start () { return iov + iovst; }
7799 int count () { return iovcnt; }
78100 };
79- LineIOV prepare_line_iov (int level_, const char * begin, const char * end) {
80- LineIOV iov;
81- unsigned int level = level_;
82- iov.total_length = end - begin;
83- iov.iov [1 ] = {(void *)begin, iov.total_length };
84- if (level >= LEN (level_prefix) || 0 == level_prefix[level].iov_len ) {
85- iov.iovst = iov.iovcnt = 1 ;
86- } else {
87- iov.iov [0 ] = level_prefix[level];
88- iov.iov [2 ] = alog_color_reset;
89- iov.total_length += iov.iov [0 ].iov_len +
90- iov.iov [2 ].iov_len ;
91- iov.iovst = 0 ; iov.iovcnt = 3 ;
92- }
93- return iov;
94- }
95101 void write (int level, const char * begin, const char * end) override {
96- auto iov = prepare_line_iov ( level, begin, end);
102+ LineIOV iov ( get_color ( level) , begin, end);
97103 std::ignore = ::writev (log_file_fd, iov.start (), iov.count ());
98104 throttle_block ();
99105 }
100106 void throttle_block () {
101107 if (throttle == -1UL ) return ;
102- time_t t = mktime (&alog_time);
103- if (t > ts) {
104- ts = t;
105- count = 0 ;
106- }
107- if (++count > throttle) {
108- std::this_thread::sleep_for (std::chrono::seconds (1 ));
109- }
108+ if (ts != now0) { ts = now0; count = 0 ; }
109+ if (++count > throttle) { ::sleep (1 ); }
110110 }
111111 virtual int get_log_file_fd () override { return log_file_fd; }
112112 virtual uint64_t set_throttle (uint64_t t = -1 ) override { return throttle = t; }
@@ -257,8 +257,11 @@ void LogFormatter::put_integer_dec(ALogBuffer& buf, ALogInteger x)
257257}
258258
259259__attribute__ ((constructor)) static void __initial_timezone() { tzset (); }
260- static time_t dayid = 0 , minuteid = 0 , tsdelta = 0 ;
261- static struct tm * alog_update_time (time_t now0) {
260+ static struct tm * alog_update_time (uint32_t now0) {
261+ static uint32_t dayid = 0 , minuteid = 0 ;
262+ static time_t tsdelta = 0 ;
263+ ::now0 = now0;
264+
262265 auto now = now0 + tsdelta;
263266 int sec = now % 60 ; now /= 60 ;
264267 if (unlikely (now != minuteid)) { // calibrate wall time every minute
@@ -481,8 +484,7 @@ class AsyncLogOutput final : public BaseLogOutput {
481484 static thread_local uint64_t index = 0 ;
482485 auto current = (++index) & (queue_num - 1 );
483486 size_t ra;
484- auto iov = prepare_line_iov (level, begin, end);
485- {
487+ LineIOV iov (get_color (level), begin, end); {
486488 SCOPED_LOCK (lock[current].get ());
487489 ra = buf[current]->read_available ();
488490 (void )buf[current]->produce_push_batch_fully (iov.total_length ,
0 commit comments