Coverage Report

Created: 2026-02-11 20:50

/root/doris/cloud/src/common/logging.cpp
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "logging.h"
19
20
#include <bthread/bthread.h>
21
#include <bthread/types.h>
22
#include <glog/logging.h>
23
#include <glog/vlog_is_on.h>
24
25
#include <iomanip>
26
#include <iostream>
27
#include <mutex>
28
29
#include "config.h"
30
31
namespace doris::cloud {
32
33
231k
static butil::LinkedList<AnnotateTag>* get_annotate_tag_list() {
34
231k
    static std::once_flag log_annotated_tags_key_once;
35
231k
    static bthread_key_t log_annotated_tags_key;
36
231k
    std::call_once(
37
231k
            log_annotated_tags_key_once,
38
231k
            +[](bthread_key_t* key) {
39
10
                bthread_key_create(
40
166
                        key, +[](void* value) {
41
166
                            delete reinterpret_cast<butil::LinkedList<AnnotateTag>*>(value);
42
166
                        });
43
10
            },
44
231k
            &log_annotated_tags_key);
45
46
231k
    auto* tag_list = reinterpret_cast<butil::LinkedList<AnnotateTag>*>(
47
231k
            bthread_getspecific(log_annotated_tags_key));
48
231k
    if (!tag_list) {
49
273
        tag_list = new butil::LinkedList<AnnotateTag>();
50
273
        bthread_setspecific(log_annotated_tags_key, tag_list);
51
273
    }
52
231k
    return tag_list;
53
231k
}
54
55
AnnotateTag::AnnotateTag(default_tag_t, std::string_view key, std::string value)
56
8.80k
        : key_(key), value_(std::move(value)) {
57
8.80k
    get_annotate_tag_list()->Append(this);
58
8.80k
}
59
60
AnnotateTag::AnnotateTag(std::string_view key, std::string_view value)
61
6.62k
        : AnnotateTag(default_tag, key, fmt::format("\"{}\"", value)) {}
62
63
8.80k
AnnotateTag::~AnnotateTag() {
64
8.80k
    RemoveFromList();
65
8.80k
}
66
67
222k
void AnnotateTag::format_tag_list(std::ostream& stream) {
68
222k
    butil::LinkedList<AnnotateTag>* list = get_annotate_tag_list();
69
222k
    butil::LinkNode<AnnotateTag>* head = list->head();
70
222k
    const butil::LinkNode<AnnotateTag>* end = list->end();
71
255k
    for (; head != end; head = head->next()) {
72
33.6k
        stream << ' ' << head->value()->key_ << '=' << head->value()->value_;
73
33.6k
    }
74
222k
}
75
76
0
void custom_prefix(std::ostream& s, const google::LogMessageInfo& l, void*) {
77
    // Add prefix "RuntimeLogger ".
78
0
    s << "RuntimeLogger ";
79
    // Same as in fe.log
80
    // The following is same as default log format. eg:
81
    // I20240605 15:25:15.677153 1763151 meta_service_txn.cpp:481] msg...
82
0
    s << l.severity[0];
83
0
    s << std::setw(4) << 1900 + l.time.year();
84
0
    s << std::setw(2) << 1 + l.time.month();
85
0
    s << std::setw(2) << l.time.day();
86
0
    s << ' ';
87
0
    s << std::setw(2) << l.time.hour() << ':';
88
0
    s << std::setw(2) << l.time.min() << ':';
89
0
    s << std::setw(2) << l.time.sec() << ".";
90
0
    s << std::setw(6) << l.time.usec();
91
0
    s << ' ';
92
0
    s << std::setfill(' ') << std::setw(5);
93
0
    s << l.thread_id << std::setfill('0');
94
0
    s << ' ';
95
0
    s << l.filename << ':' << l.line_number << "]";
96
0
}
97
98
// Implement the custom log format for stdout output in K8S environment
99
// Format: I20240605 15:25:15.677153 1763151 meta_service_txn.cpp:481] msg...
100
struct StdoutLogSink : google::LogSink {
101
    void send(google::LogSeverity severity, const char* /*full_filename*/,
102
              const char* base_filename, int line, const google::LogMessageTime& time,
103
0
              const char* message, std::size_t message_len) override {
104
        // Convert log severity to corresponding character (I/W/E/F)
105
0
        char severity_char;
106
0
        switch (severity) {
107
0
        case google::GLOG_INFO:
108
0
            severity_char = 'I';
109
0
            break;
110
0
        case google::GLOG_WARNING:
111
0
            severity_char = 'W';
112
0
            break;
113
0
        case google::GLOG_ERROR:
114
0
            severity_char = 'E';
115
0
            break;
116
0
        case google::GLOG_FATAL:
117
0
            severity_char = 'F';
118
0
            break;
119
0
        default:
120
0
            severity_char = '?';
121
0
            break;
122
0
        }
123
124
        // Set output formatting flags
125
0
        std::cout << std::setfill('0');
126
127
        // 1. Log severity (I/W/E/F)
128
0
        std::cout << severity_char;
129
130
        // 2. Date (YYYYMMDD)
131
        // Note: tm_year is years since 1900, tm_mon is 0-based (0-11)
132
0
        std::cout << std::setw(4) << (time.year() + 1900) << std::setw(2) << std::setfill('0')
133
0
                  << (time.month() + 1) << std::setw(2) << std::setfill('0') << time.day();
134
135
        // 3. Time (HH:MM:SS.ffffff)
136
0
        std::cout << " " << std::setw(2) << std::setfill('0') << time.hour() << ":" << std::setw(2)
137
0
                  << std::setfill('0') << time.min() << ":" << std::setw(2) << std::setfill('0')
138
0
                  << time.sec() << "." << std::setw(6) << std::setfill('0') << time.usec();
139
140
        // 4. Thread ID
141
0
        std::cout << " " << std::setfill(' ') << std::setw(5) << getpid() << std::setfill('0');
142
143
        // 5. Filename and line number
144
0
        std::cout << " " << base_filename << ":" << line << "] ";
145
146
        // 6. Log message
147
0
        std::cout.write(message, message_len);
148
149
        // Add newline and flush
150
0
        std::cout << std::endl;
151
0
    }
152
};
153
154
static StdoutLogSink stdout_log_sink;
155
156
/**
157
 * @param basename the basename of log file
158
 * @return true for success
159
 */
160
22
bool init_glog(const char* basename) {
161
22
    static std::mutex mtx;
162
22
    static bool inited = false;
163
22
    std::lock_guard<std::mutex> logging_lock(mtx);
164
22
    if (inited) return true;
165
166
18
    bool log_to_console = (getenv("DORIS_LOG_TO_STDERR") != nullptr);
167
18
    if (log_to_console) {
168
0
        if (config::enable_file_logger) {
169
            // will output log to log file and output log to stdout
170
0
            google::AddLogSink(&stdout_log_sink);
171
0
        } else {
172
            // enable_file_logger is false, will only output log to stdout
173
            // Not output to stderr because doris_cloud.out will output log to stderr
174
0
            FLAGS_logtostdout = true;
175
0
        }
176
18
    } else {
177
18
        FLAGS_alsologtostderr = false;
178
18
    }
179
180
    // Don't log to stderr except fatal level
181
    // so fatal log can output to doris_cloud.out .
182
18
    FLAGS_stderrthreshold = google::FATAL;
183
184
    // Set glog log dir
185
18
    FLAGS_log_dir = config::log_dir;
186
    // Buffer log messages for at most this many seconds
187
18
    FLAGS_logbufsecs = 1;
188
    // Set log roll mode
189
    // Candidates: day, hour, size
190
18
    FLAGS_log_split_method = "size";
191
    // Sets the maximum log file size (in MB).
192
18
    FLAGS_max_log_size = config::log_size_mb;
193
    // Set roll num
194
18
    FLAGS_log_filenum_quota = config::log_filenum_quota;
195
196
18
#ifdef GLOG_HAS_WARN_LOG_FILENUM_QUOTA
197
    // Set warn log roll num
198
18
    FLAGS_warn_log_filenum_quota = config::warn_log_filenum_quota;
199
18
#endif
200
201
    // clang-format off
202
    // set log level
203
18
    std::string& loglevel = config::log_level;
204
    // Can be 0 1 2 3 ... the larger the higher level for logging,
205
    // corrensponding to INFO WARNING ERROR FATAL
206
    // const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3, NUM_SEVERITIES = 4;
207
56
    auto tolower = [](std::string s) { for (auto& i : s) i |= 0x20; return s; };
208
18
    FLAGS_minloglevel = tolower(loglevel) == "info"  ? 0
209
18
                      : tolower(loglevel) == "warn"  ? 1
210
4
                      : tolower(loglevel) == "error" ? 2
211
4
                      : tolower(loglevel) == "fatal" ? 3
212
4
                      :                                0; // Default INFO
213
    // clang-format on
214
215
    // Log messages at a level <= this flag are buffered.
216
    // Log messages at a higher level are flushed immediately.
217
18
    FLAGS_logbuflevel = config::log_immediate_flush ? -1 : 0;
218
219
    // Set verbose modules
220
18
    FLAGS_v = -1;
221
18
    for (auto& i : config::log_verbose_modules) {
222
0
        if (i.empty()) continue;
223
0
        google::SetVLOGLevel(i.c_str(), config::log_verbose_level);
224
0
    }
225
18
    if (log_to_console) {
226
        // Only add prefix if log output to stderr
227
0
        google::InitGoogleLogging(basename, &custom_prefix);
228
18
    } else {
229
18
        google::InitGoogleLogging(basename);
230
18
    }
231
18
    inited = true;
232
18
    return true;
233
22
}
234
235
} // namespace doris::cloud