wangrong
2025-01-18 8b0e31121a9a29b92a41fc575138a2e9b4c12d8e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
 
#include "vp_logger.h"
 
namespace vp_utils {
        
    vp_logger::vp_logger(/* args */)
    {
    }
    
    vp_logger::~vp_logger() {
        die();
        if (log_writer_th.joinable()) {
            log_writer_th.join();
        }
    }
 
    void vp_logger::die() {
        alive = false;
        std::lock_guard<std::mutex> guard(log_cache_mutex);
        log_cache.push("die");
        log_cache_semaphore.signal();
    }
 
    void vp_logger::init() {
        inited = true;
 
        // initialize file writer
        file_writer.init(log_dir, log_file_name_template);
 
        #ifdef VP_WITH_KAFKA
        // initialize kafka writer
        auto servers_and_topic = vp_utils::string_split(kafka_servers_and_topic, '/');
        assert(servers_and_topic.size() == 2);
        kafka_writer.init(servers_and_topic[0], servers_and_topic[1]);
        #endif
 
        // run thread
        auto t = std::thread(&vp_logger::log_write_run, this); 
        log_writer_th = std::move(t);
    }
 
    void vp_logger::log(vp_log_level level, const std::string& message, const char* code_file, int code_line) {
        // make sure logger is initialized
        if (!inited) {
            throw "vp_logger is not initialized yet!";
        }
        
        // level filter
        if (level > log_level) {
            return;
        }
        
        // keywords filter for debug level
        if (level == vp_log_level::DEBUG && keywords_for_debug_log.size() != 0) {
            bool filterd = true;
            for(auto& keywords: keywords_for_debug_log) {
                if (message.find(keywords) != std::string::npos) {
                    filterd = false;
                    break;
                }
            }
            if (filterd) {
                return;
            }
        }
        
        /* create log */
        std::string new_log = "";
        // 100% true for log time
        if (include_time) {
            new_log += vp_utils::time_format(NOW, log_time_templete);
        }
 
        // log level
        if (include_level) {
            new_log += "[" + log_level_names.at(level) + "]";
        }
 
        // thread id
        if (include_thread_id) {
            auto id = std::this_thread::get_id();
            std::stringstream ss;
            ss << std::hex << id;  // to hex
            auto thread_id = ss.str(); 
            new_log += "[" + thread_id + "]";
        }
        
        // code location
        if (include_code_location) {
            new_log += "[" + std::string(code_file) + ":" + std::to_string(code_line) + "]";
        }
 
        new_log += " " + message;
 
        /* write to cache */
        // min lock range
        std::lock_guard<std::mutex> guard(log_cache_mutex);
        log_cache.push(new_log);
        // notify
        log_cache_semaphore.signal();
    }
 
    void vp_logger::log_write_run() {
        bool log_thres_warned = false;
        /* below code runs in single thread */
        while (inited && alive) {
            // wait for data
            log_cache_semaphore.wait();
            auto log = log_cache.front();
            log_cache.pop();
 
            if (log == "die") {
                continue;
            }
            
            /* watch the log cache size */
            auto log_cache_size = 0;
            {
                // min lock range
                std::lock_guard<std::mutex> guard(log_cache_mutex);
                log_cache_size = log_cache.size();
            }
            if (!log_thres_warned && log_cache_size > log_cache_warn_threshold) {
                VP_WARN(vp_utils::string_format("[logger] log cache size is exceeding threshold! cache size is: [%d], threshold is: [%d]", log_cache_size, log_cache_warn_threshold));
                log_thres_warned = true;  // warn 1 time
            }
            if (log_cache_size <= log_cache_warn_threshold) {
                log_thres_warned = false;
            }
            
            /* write to devices */
            if (log_to_console) {
                write_to_console(log);
            }
            
            if (log_to_file) {
                write_to_file(log);
            }
 
            if (log_to_kafka) {
                write_to_kafka(log);
            }
        }
    }
 
    void vp_logger::write_to_console(const std::string& log) {
        std::cout << log << std::endl;
    }
 
    void vp_logger::write_to_file(const std::string& log) {
        // file_writer.write(log);
        file_writer << log;
    }
 
    void vp_logger::write_to_kafka(const std::string& log) {
        #ifdef VP_WITH_KAFKA
        // kafka_writer.write(log);
        kafka_writer << log;
        #endif
    }
}