/Users/deen/code/yugabyte-db/src/yb/util/debug/trace_logging.h
Line | Count | Source |
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 | | // This header defines the following macro: |
33 | | // |
34 | | // VLOG_AND_TRACE(category, vlevel) |
35 | | // |
36 | | // Write a log message to VLOG(vlevel) as well as the current |
37 | | // trace event buffer as an "INSTANT" trace event type. If the |
38 | | // given vlog level is not enabled, this will still result in a |
39 | | // trace buffer entry. |
40 | | // |
41 | | // The provided 'category' should be a trace event category, which |
42 | | // allows the users to filter which trace events to enable. |
43 | | // For example: |
44 | | // |
45 | | // VLOG_AND_TRACE("my_subsystem", 1) << "This always shows up in trace buffers " |
46 | | // << "but only shows up in the log if VLOG(1) level logging is enabled."; |
47 | | // |
48 | | // Most VLOG(1) level log messages are reasonable to use this macro. |
49 | | // Note that there is slightly more overhead to this macro as opposed |
50 | | // to just using VLOG(1). |
51 | | // |
52 | | // Note that, like VLOG(n), this macro avoids evaluating its arguments unless |
53 | | // either trace recording or VLOG(n) is enabled. In the case that both are enabled, |
54 | | // the arguments are only evaluated once. |
55 | | // |
56 | | #ifndef YB_DEBUG_TRACE_LOGGING_H |
57 | | #define YB_DEBUG_TRACE_LOGGING_H |
58 | | |
59 | | #include <glog/logging.h> |
60 | | #include <string> |
61 | | |
62 | | #include "yb/gutil/macros.h" |
63 | | #include "yb/util/debug/trace_event.h" |
64 | | |
65 | | // The inner workings of these macros are a bit arcane: |
66 | | // - We make use of the fact that a block can be embedded within a ternary expression. |
67 | | // This allows us to determine whether the trace event is enabled before we decide |
68 | | // to evaluate the arguments. |
69 | | // - We have to use google::LogMessageVoidify so that we can put 'void(0)' on one side |
70 | | // of the ternary expression and the log stream on the other. This technique is |
71 | | // cribbed from glog/logging.h. |
72 | | #define VLOG_AND_TRACE_INTERNAL(category, vlevel) \ |
73 | 1.29M | yb::debug::TraceVLog(__FILE__, __LINE__, category, VLOG_IS_ON(vlevel)).stream() |
74 | | #define VLOG_AND_TRACE(category, vlevel) \ |
75 | 1.29M | !( { \ |
76 | 1.29M | bool enabled; \ |
77 | 1.29M | TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &enabled); \ |
78 | 1.29M | enabled || VLOG_IS_ON(vlevel); \ |
79 | 1.29M | } ) ? static_cast<void>(0) : \ |
80 | 18.4E | google::LogMessageVoidify() & VLOG_AND_TRACE_INTERNAL(category, vlevel) |
81 | | |
82 | | namespace yb { |
83 | | namespace debug { |
84 | | |
85 | | class TraceVLog { |
86 | | public: |
87 | | TraceVLog(const char* file, int line, const char* category, bool do_vlog) |
88 | | : sink_(category), |
89 | 4 | google_msg_(file, line, google::GLOG_INFO, &sink_, do_vlog) { |
90 | 4 | } |
91 | | |
92 | 4 | std::ostream& stream() { |
93 | 4 | return google_msg_.stream(); |
94 | 4 | } |
95 | | |
96 | | private: |
97 | | class TraceLogSink : public google::LogSink { |
98 | | public: |
99 | 4 | explicit TraceLogSink(const char* category) : category_(category) {} |
100 | | void send(google::LogSeverity severity, const char* full_filename, |
101 | | const char* base_filename, int line, |
102 | | const struct ::tm* tm_time, const char* message, |
103 | 4 | size_t message_len) override { |
104 | | // Rather than calling TRACE_EVENT_INSTANT here, we have to do it from |
105 | | // the destructor. This is because glog holds its internal mutex while |
106 | | // calling send(). So, if we try to use TRACE_EVENT here, and --trace_to_console |
107 | | // is enabled, then we'd end up calling back into glog when its lock is already |
108 | | // held. glog isn't re-entrant, so that causes a crash. |
109 | | // |
110 | | // By just storing the string here, and then emitting the trace in the dtor, |
111 | | // we defer the tracing until the google::LogMessage has destructed and the |
112 | | // glog lock is available again. |
113 | 4 | str_ = ToString(severity, base_filename, line, |
114 | 4 | tm_time, message, message_len); |
115 | 4 | } |
116 | 4 | virtual ~TraceLogSink() { |
117 | 4 | TRACE_EVENT_INSTANT1(category_, "vlog", TRACE_EVENT_SCOPE_THREAD, |
118 | 4 | "msg", str_); |
119 | 4 | } |
120 | | |
121 | | private: |
122 | | const char* const category_; |
123 | | std::string str_; |
124 | | }; |
125 | | |
126 | | TraceLogSink sink_; |
127 | | google::LogMessage google_msg_; |
128 | | }; |
129 | | |
130 | | } // namespace debug |
131 | | } // namespace yb |
132 | | #endif /* YB_DEBUG_TRACE_LOGGING_H */ |