YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/trace.cc
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
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include "yb/util/trace.h"
34
35
#include <iomanip>
36
#include <iostream>
37
#include <string>
38
#include <vector>
39
40
#include <boost/range/adaptor/indirected.hpp>
41
42
#include "yb/gutil/strings/substitute.h"
43
#include "yb/gutil/walltime.h"
44
45
#include "yb/util/flag_tags.h"
46
#include "yb/util/memory/arena.h"
47
#include "yb/util/memory/memory.h"
48
#include "yb/util/object_pool.h"
49
#include "yb/util/size_literals.h"
50
51
DEFINE_bool(enable_tracing, false, "Flag to enable/disable tracing across the code.");
52
TAG_FLAG(enable_tracing, advanced);
53
TAG_FLAG(enable_tracing, runtime);
54
55
DEFINE_bool(use_monotime_for_traces, false, "Flag to enable use of MonoTime::Now() instead of "
56
    "CoarseMonoClock::Now(). CoarseMonoClock is much cheaper so it is better to use it. However "
57
    "if we need more accurate sub-millisecond level breakdown, we could use MonoTime.");
58
TAG_FLAG(use_monotime_for_traces, advanced);
59
TAG_FLAG(use_monotime_for_traces, runtime);
60
61
DEFINE_int32(tracing_level, 0, "verbosity levels (like --v) up to which tracing is enabled.");
62
TAG_FLAG(tracing_level, advanced);
63
TAG_FLAG(tracing_level, runtime);
64
65
DEFINE_int32(print_nesting_levels, 5, "controls the depth of the child traces to be printed.");
66
TAG_FLAG(print_nesting_levels, advanced);
67
TAG_FLAG(print_nesting_levels, runtime);
68
69
namespace yb {
70
71
using strings::internal::SubstituteArg;
72
73
__thread Trace* Trace::threadlocal_trace_;
74
75
namespace {
76
77
const char* kNestedChildPrefix = "..  ";
78
79
// Get the part of filepath after the last path separator.
80
// (Doesn't modify filepath, contrary to basename() in libgen.h.)
81
// Borrowed from glog.
82
49.0k
const char* const_basename(const char* filepath) {
83
49.0k
  const char* base = strrchr(filepath, '/');
84
49.0k
  return base ? 
(base + 1)49.0k
:
filepath1
;
85
49.0k
}
86
87
template <class Children>
88
void DumpChildren(
89
12.6k
    std::ostream* out, int32_t tracing_depth, bool include_time_deltas, const Children* children) {
90
12.6k
  if (tracing_depth > GetAtomicFlag(&FLAGS_print_nesting_levels)) {
91
0
    return;
92
0
  }
93
12.6k
  for (auto &child_trace : *children) {
94
13.3k
    for (int i = 0; i < tracing_depth; 
i++8.42k
) {
95
8.42k
      *out << kNestedChildPrefix;
96
8.42k
    }
97
4.92k
    *out << "Related trace:" << std::endl;
98
4.92k
    *out << child_trace->DumpToString(tracing_depth, include_time_deltas);
99
4.92k
  }
100
12.6k
}
101
102
void DumpChildren(
103
0
    std::ostream* out, int32_t tracing_depth, bool include_time_deltas, std::nullptr_t children) {}
104
105
template <class Entries>
106
void DumpEntries(
107
    std::ostream* out,
108
    int32_t tracing_depth,
109
    bool include_time_deltas,
110
    int64_t start,
111
12.6k
    const Entries& entries) {
112
12.6k
  if (entries.empty()) {
113
1.77k
    return;
114
1.77k
  }
115
116
10.8k
  auto time_usec = MonoDelta(entries.begin()->timestamp.time_since_epoch()).ToMicroseconds();
117
10.8k
  const int64_t time_correction_usec = start - time_usec;
118
10.8k
  int64_t prev_usecs = time_usec;
119
49.0k
  for (const auto& e : entries) {
120
49.0k
    time_usec = MonoDelta(e.timestamp.time_since_epoch()).ToMicroseconds();
121
49.0k
    const int64_t usecs_since_prev = time_usec - prev_usecs;
122
49.0k
    prev_usecs = time_usec;
123
124
49.0k
    const auto absolute_time_usec = time_usec + time_correction_usec;
125
49.0k
    const time_t secs_since_epoch = absolute_time_usec / 1000000;
126
49.0k
    const int usecs = absolute_time_usec % 1000000;
127
49.0k
    struct tm tm_time;
128
49.0k
    localtime_r(&secs_since_epoch, &tm_time);
129
130
103k
    for (int i = 0; i < tracing_depth; 
i++54.2k
) {
131
54.2k
      *out << kNestedChildPrefix;
132
54.2k
    }
133
    // Log format borrowed from glog/logging.cc
134
49.0k
    using std::setw;
135
49.0k
    out->fill('0');
136
137
49.0k
    *out << setw(2) << (1 + tm_time.tm_mon)
138
49.0k
         << setw(2) << tm_time.tm_mday
139
49.0k
         << ' '
140
49.0k
         << setw(2) << tm_time.tm_hour  << ':'
141
49.0k
         << setw(2) << tm_time.tm_min   << ':'
142
49.0k
         << setw(2) << tm_time.tm_sec   << '.'
143
49.0k
         << setw(6) << usecs << ' ';
144
49.0k
    if (include_time_deltas) {
145
49.0k
      out->fill(' ');
146
49.0k
      *out << "(+" << setw(6) << usecs_since_prev << "us) ";
147
49.0k
    }
148
49.0k
    e.Dump(out);
149
49.0k
    *out << std::endl;
150
49.0k
  }
151
10.8k
}
trace.cc:void yb::(anonymous namespace)::DumpEntries<boost::range_detail::indirected_range<std::__1::vector<yb::TraceEntry*, std::__1::allocator<yb::TraceEntry*> > > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >*, int, bool, long long, boost::range_detail::indirected_range<std::__1::vector<yb::TraceEntry*, std::__1::allocator<yb::TraceEntry*> > > const&)
Line
Count
Source
111
12.6k
    const Entries& entries) {
112
12.6k
  if (entries.empty()) {
113
1.77k
    return;
114
1.77k
  }
115
116
10.8k
  auto time_usec = MonoDelta(entries.begin()->timestamp.time_since_epoch()).ToMicroseconds();
117
10.8k
  const int64_t time_correction_usec = start - time_usec;
118
10.8k
  int64_t prev_usecs = time_usec;
119
49.0k
  for (const auto& e : entries) {
120
49.0k
    time_usec = MonoDelta(e.timestamp.time_since_epoch()).ToMicroseconds();
121
49.0k
    const int64_t usecs_since_prev = time_usec - prev_usecs;
122
49.0k
    prev_usecs = time_usec;
123
124
49.0k
    const auto absolute_time_usec = time_usec + time_correction_usec;
125
49.0k
    const time_t secs_since_epoch = absolute_time_usec / 1000000;
126
49.0k
    const int usecs = absolute_time_usec % 1000000;
127
49.0k
    struct tm tm_time;
128
49.0k
    localtime_r(&secs_since_epoch, &tm_time);
129
130
103k
    for (int i = 0; i < tracing_depth; 
i++54.2k
) {
131
54.2k
      *out << kNestedChildPrefix;
132
54.2k
    }
133
    // Log format borrowed from glog/logging.cc
134
49.0k
    using std::setw;
135
49.0k
    out->fill('0');
136
137
49.0k
    *out << setw(2) << (1 + tm_time.tm_mon)
138
49.0k
         << setw(2) << tm_time.tm_mday
139
49.0k
         << ' '
140
49.0k
         << setw(2) << tm_time.tm_hour  << ':'
141
49.0k
         << setw(2) << tm_time.tm_min   << ':'
142
49.0k
         << setw(2) << tm_time.tm_sec   << '.'
143
49.0k
         << setw(6) << usecs << ' ';
144
49.0k
    if (include_time_deltas) {
145
49.0k
      out->fill(' ');
146
49.0k
      *out << "(+" << setw(6) << usecs_since_prev << "us) ";
147
49.0k
    }
148
49.0k
    e.Dump(out);
149
49.0k
    *out << std::endl;
150
49.0k
  }
151
10.8k
}
Unexecuted instantiation: trace.cc:void yb::(anonymous namespace)::DumpEntries<boost::iterator_range<yb::PlainTrace::Entry const*> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >*, int, bool, long long, boost::iterator_range<yb::PlainTrace::Entry const*> const&)
152
153
template <class Entries, class Children>
154
void DoDump(
155
    std::ostream* out,
156
    int32_t tracing_depth,
157
    bool include_time_deltas,
158
    int64_t start,
159
    const Entries& entries,
160
12.6k
    Children children) {
161
  // Save original flags.
162
12.6k
  std::ios::fmtflags save_flags(out->flags());
163
164
12.6k
  DumpEntries(out, tracing_depth, include_time_deltas, start, entries);
165
12.6k
  DumpChildren(out, tracing_depth + 1, include_time_deltas, children);
166
167
  // Restore stream flags.
168
12.6k
  out->flags(save_flags);
169
12.6k
}
trace.cc:void yb::(anonymous namespace)::DoDump<boost::range_detail::indirected_range<std::__1::vector<yb::TraceEntry*, std::__1::allocator<yb::TraceEntry*> > >, std::__1::vector<scoped_refptr<yb::Trace>, std::__1::allocator<scoped_refptr<yb::Trace> > >*>(std::__1::basic_ostream<char, std::__1::char_traits<char> >*, int, bool, long long, boost::range_detail::indirected_range<std::__1::vector<yb::TraceEntry*, std::__1::allocator<yb::TraceEntry*> > > const&, std::__1::vector<scoped_refptr<yb::Trace>, std::__1::allocator<scoped_refptr<yb::Trace> > >*)
Line
Count
Source
160
12.6k
    Children children) {
161
  // Save original flags.
162
12.6k
  std::ios::fmtflags save_flags(out->flags());
163
164
12.6k
  DumpEntries(out, tracing_depth, include_time_deltas, start, entries);
165
12.6k
  DumpChildren(out, tracing_depth + 1, include_time_deltas, children);
166
167
  // Restore stream flags.
168
12.6k
  out->flags(save_flags);
169
12.6k
}
Unexecuted instantiation: trace.cc:void yb::(anonymous namespace)::DoDump<boost::iterator_range<yb::PlainTrace::Entry const*>, std::nullptr_t>(std::__1::basic_ostream<char, std::__1::char_traits<char> >*, int, bool, long long, boost::iterator_range<yb::PlainTrace::Entry const*> const&, std::nullptr_t)
170
171
std::once_flag init_get_current_micros_fast_flag;
172
int64_t initial_micros_offset;
173
174
4.81k
void InitGetCurrentMicrosFast() {
175
4.81k
  auto before = CoarseMonoClock::Now();
176
4.81k
  initial_micros_offset = GetCurrentTimeMicros();
177
4.81k
  auto after = CoarseMonoClock::Now();
178
4.81k
  auto mid = MonoDelta(after.time_since_epoch() + before.time_since_epoch()).ToMicroseconds() / 2;
179
4.81k
  initial_micros_offset -= mid;
180
4.81k
}
181
182
89.8M
int64_t GetCurrentMicrosFast(CoarseTimePoint now) {
183
89.8M
  std::call_once(init_get_current_micros_fast_flag, InitGetCurrentMicrosFast);
184
89.8M
  return initial_micros_offset + MonoDelta(now.time_since_epoch()).ToMicroseconds();
185
89.8M
}
186
187
} // namespace
188
189
ScopedAdoptTrace::ScopedAdoptTrace(Trace* t)
190
293M
    : old_trace_(Trace::threadlocal_trace_), is_enabled_(GetAtomicFlag(&FLAGS_enable_tracing)) {
191
293M
  if (is_enabled_) {
192
78.4M
    trace_ = t;
193
78.4M
    Trace::threadlocal_trace_ = t;
194
78.4M
    DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_);
195
78.4M
  }
196
293M
}
197
198
293M
ScopedAdoptTrace::~ScopedAdoptTrace() {
199
293M
  if (is_enabled_) {
200
78.4M
    Trace::threadlocal_trace_ = old_trace_;
201
    // It's critical that we Release() the reference count on 't' only
202
    // after we've unset the thread-local variable. Otherwise, we can hit
203
    // a nasty interaction with tcmalloc contention profiling. Consider
204
    // the following sequence:
205
    //
206
    //   1. threadlocal_trace_ has refcount = 1
207
    //   2. we call threadlocal_trace_->Release() which decrements refcount to 0
208
    //   3. this calls 'delete' on the Trace object
209
    //   3a. this calls tcmalloc free() on the Trace and various sub-objects
210
    //   3b. the free() calls may end up experiencing contention in tcmalloc
211
    //   3c. we try to account the contention in threadlocal_trace_'s TraceMetrics,
212
    //       but it has already been freed.
213
    //
214
    // In the best case, we just scribble into some free tcmalloc memory. In the
215
    // worst case, tcmalloc would have already re-used this memory for a new
216
    // allocation on another thread, and we end up overwriting someone else's memory.
217
    //
218
    // Waiting to Release() only after 'unpublishing' the trace solves this.
219
78.4M
    trace_.reset();
220
78.4M
    DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_);
221
78.4M
  }
222
293M
}
223
224
// Struct which precedes each entry in the trace.
225
struct TraceEntry {
226
  CoarseTimePoint timestamp;
227
228
  // The source file and line number which generated the trace message.
229
  const char* file_path;
230
  int line_number;
231
232
  size_t message_len;
233
  TraceEntry* next;
234
  char message[0];
235
236
49.0k
  void Dump(std::ostream* out) const {
237
49.0k
    *out << const_basename(file_path) << ':' << line_number
238
49.0k
         << "] ";
239
49.0k
    out->write(message, message_len);
240
49.0k
  }
241
};
242
243
258M
Trace::Trace() {
244
258M
}
245
246
179M
ThreadSafeObjectPool<ThreadSafeArena>& ArenaPool() {
247
179M
  static ThreadSafeObjectPool<ThreadSafeArena> result([] {
248
26.7M
    return new ThreadSafeArena(8_KB, 128_KB);
249
26.7M
  });
250
179M
  return result;
251
179M
}
252
253
258M
Trace::~Trace() {
254
258M
  auto* arena = arena_.load(std::memory_order_acquire);
255
258M
  if (arena) {
256
89.7M
    arena->Reset();
257
89.7M
    ArenaPool().Release(arena);
258
89.7M
  }
259
258M
}
260
261
544M
ThreadSafeArena* Trace::GetAndInitArena() {
262
544M
  auto* arena = arena_.load(std::memory_order_acquire);
263
544M
  if (arena == nullptr) {
264
89.7M
    arena = ArenaPool().Take();
265
89.7M
    ThreadSafeArena* existing_arena = nullptr;
266
89.7M
    if (
arena_.compare_exchange_strong(existing_arena, arena, std::memory_order_release)89.7M
) {
267
89.7M
      return arena;
268
18.4E
    } else {
269
18.4E
      ArenaPool().Release(arena);
270
18.4E
      return existing_arena;
271
18.4E
    }
272
89.7M
  }
273
454M
  return arena;
274
544M
}
275
276
void Trace::SubstituteAndTrace(
277
442M
    const char* file_path, int line_number, CoarseTimePoint now, GStringPiece format) {
278
442M
  auto msg_len = format.size();
279
442M
  DCHECK_NE
(msg_len, 0) << "Bad format specification"0
;
280
442M
  TraceEntry* entry = NewEntry(msg_len, file_path, line_number, now);
281
442M
  if (entry == nullptr) 
return0
;
282
442M
  memcpy(entry->message, format.data(), msg_len);
283
442M
  AddEntry(entry);
284
442M
}
285
286
void Trace::SubstituteAndTrace(const char* file_path,
287
                               int line_number,
288
                               CoarseTimePoint now,
289
                               GStringPiece format,
290
                               const SubstituteArg& arg0, const SubstituteArg& arg1,
291
                               const SubstituteArg& arg2, const SubstituteArg& arg3,
292
                               const SubstituteArg& arg4, const SubstituteArg& arg5,
293
                               const SubstituteArg& arg6, const SubstituteArg& arg7,
294
102M
                               const SubstituteArg& arg8, const SubstituteArg& arg9) {
295
102M
  const SubstituteArg* const args_array[] = {
296
102M
    &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, nullptr
297
102M
  };
298
299
102M
  int msg_len = strings::internal::SubstitutedSize(format, args_array);
300
102M
  DCHECK_NE
(msg_len, 0) << "Bad format specification"0
;
301
102M
  TraceEntry* entry = NewEntry(msg_len, file_path, line_number, now);
302
102M
  if (entry == nullptr) 
return0
;
303
102M
  SubstituteToBuffer(format, args_array, entry->message);
304
102M
  AddEntry(entry);
305
102M
}
306
307
TraceEntry* Trace::NewEntry(
308
543M
    size_t msg_len, const char* file_path, int line_number, CoarseTimePoint now) {
309
543M
  auto* arena = GetAndInitArena();
310
543M
  size_t size = offsetof(TraceEntry, message) + msg_len;
311
543M
  void* dst = arena->AllocateBytesAligned(size, alignof(TraceEntry));
312
543M
  if (dst == nullptr) {
313
0
    LOG(ERROR) << "NewEntry(msg_len, " << file_path << ", " << line_number
314
0
        << ") received nullptr from AllocateBytes.\n So far:" << DumpToString(true);
315
0
    return nullptr;
316
0
  }
317
543M
  TraceEntry* entry = new (dst) TraceEntry;
318
543M
  entry->timestamp = now;
319
543M
  entry->message_len = msg_len;
320
543M
  entry->file_path = file_path;
321
543M
  entry->line_number = line_number;
322
543M
  return entry;
323
543M
}
324
325
544M
void Trace::AddEntry(TraceEntry* entry) {
326
544M
  std::lock_guard<simple_spinlock> l(lock_);
327
544M
  entry->next = nullptr;
328
329
544M
  if (entries_tail_ != nullptr) {
330
455M
    entries_tail_->next = entry;
331
455M
  } else {
332
89.1M
    DCHECK(entries_head_ == nullptr);
333
89.1M
    entries_head_ = entry;
334
89.1M
    trace_start_time_usec_ = GetCurrentMicrosFast(entry->timestamp);
335
89.1M
  }
336
544M
  entries_tail_ = entry;
337
544M
}
338
339
275
void Trace::Dump(std::ostream *out, bool include_time_deltas) const {
340
275
  Dump(out, 0, include_time_deltas);
341
275
}
342
343
12.6k
void Trace::Dump(std::ostream* out, int32_t tracing_depth, bool include_time_deltas) const {
344
  // Gather a copy of the list of entries under the lock. This is fast
345
  // enough that we aren't worried about stalling concurrent tracers
346
  // (whereas doing the logging itself while holding the lock might be
347
  // too slow, if the output stream is a file, for example).
348
12.6k
  vector<TraceEntry*> entries;
349
12.6k
  vector<scoped_refptr<Trace> > child_traces;
350
12.6k
  decltype(trace_start_time_usec_) trace_start_time_usec;
351
12.6k
  {
352
12.6k
    std::lock_guard<simple_spinlock> l(lock_);
353
12.6k
    for (TraceEntry* cur = entries_head_;
354
61.6k
        cur != nullptr;
355
49.0k
        cur = cur->next) {
356
49.0k
      entries.push_back(cur);
357
49.0k
    }
358
359
12.6k
    child_traces = child_traces_;
360
12.6k
    trace_start_time_usec = trace_start_time_usec_;
361
12.6k
  }
362
363
12.6k
  DoDump(
364
12.6k
      out, tracing_depth, include_time_deltas, trace_start_time_usec,
365
12.6k
      entries | boost::adaptors::indirected, &child_traces);
366
12.6k
}
367
368
12.3k
string Trace::DumpToString(int32_t tracing_depth, bool include_time_deltas) const {
369
12.3k
  std::stringstream s;
370
12.3k
  Dump(&s, tracing_depth, include_time_deltas);
371
12.3k
  return s.str();
372
12.3k
}
373
374
0
void Trace::DumpCurrentTrace() {
375
0
  Trace* t = CurrentTrace();
376
0
  if (t == nullptr) {
377
0
    LOG(INFO) << "No trace is currently active.";
378
0
    return;
379
0
  }
380
0
  t->Dump(&std::cerr, true);
381
0
}
382
383
9.61M
void Trace::AddChildTrace(Trace* child_trace) {
384
9.61M
  CHECK_NOTNULL(child_trace);
385
9.61M
  {
386
9.61M
    std::lock_guard<simple_spinlock> l(lock_);
387
9.61M
    scoped_refptr<Trace> ptr(child_trace);
388
9.61M
    child_traces_.push_back(ptr);
389
9.61M
  }
390
9.61M
  CHECK(!child_trace->HasOneRef());
391
9.61M
}
392
393
144M
size_t Trace::DynamicMemoryUsage() const {
394
144M
  auto arena = arena_.load();
395
144M
  return arena ? 
arena->memory_footprint()79.2M
:
064.8M
;
396
144M
}
397
398
0
PlainTrace::PlainTrace() {
399
0
}
400
401
0
void PlainTrace::Trace(const char *file_path, int line_number, const char *message) {
402
0
  auto timestamp = CoarseMonoClock::Now();
403
0
  {
404
0
    std::lock_guard<decltype(mutex_)> lock(mutex_);
405
0
    if (size_ < kMaxEntries) {
406
0
      if (size_ == 0) {
407
0
        trace_start_time_usec_ = GetCurrentMicrosFast(timestamp);
408
0
      }
409
0
      entries_[size_] = {file_path, line_number, message, timestamp};
410
0
      ++size_;
411
0
    }
412
0
  }
413
0
}
414
415
0
void PlainTrace::Dump(std::ostream *out, bool include_time_deltas) const {
416
0
  Dump(out, 0, include_time_deltas);
417
0
}
418
419
0
void PlainTrace::Dump(std::ostream* out, int32_t tracing_depth, bool include_time_deltas) const {
420
0
  size_t size;
421
0
  decltype(trace_start_time_usec_) trace_start_time_usec;
422
0
  {
423
0
    std::lock_guard<decltype(mutex_)> lock(mutex_);
424
0
    size = size_;
425
0
    trace_start_time_usec = trace_start_time_usec_;
426
0
  }
427
0
  auto entries = boost::make_iterator_range(entries_, entries_ + size);
428
0
  DoDump(
429
0
      out, tracing_depth, include_time_deltas, trace_start_time_usec, entries,
430
0
      /* children */ nullptr);
431
0
}
432
433
0
std::string PlainTrace::DumpToString(int32_t tracing_depth, bool include_time_deltas) const {
434
0
  std::stringstream s;
435
0
  Dump(&s, tracing_depth, include_time_deltas);
436
0
  return s.str();
437
0
}
438
439
0
void PlainTrace::Entry::Dump(std::ostream *out) const {
440
0
  *out << const_basename(file_path) << ':' << line_number << "] " << message;
441
0
}
442
443
} // namespace yb