YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/server/tracing-path-handlers.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/server/tracing-path-handlers.h"
34
35
#include <functional>
36
#include <map>
37
#include <string>
38
#include <utility>
39
#include <vector>
40
41
#include <rapidjson/document.h>
42
#include <rapidjson/prettywriter.h> // NOLINT
43
#include <rapidjson/rapidjson.h> // NOLINT
44
#include <rapidjson/stringbuffer.h> // NOLINT
45
46
#include "yb/gutil/strings/escaping.h"
47
48
#include "yb/util/debug/trace_event_impl.h"
49
#include "yb/util/jsonwriter.h"
50
#include "yb/util/monotime.h"
51
#include "yb/util/status.h"
52
53
namespace yb {
54
namespace server {
55
56
using std::map;
57
using std::string;
58
using std::stringstream;
59
using std::vector;
60
61
using yb::debug::CategoryFilter;
62
using yb::debug::TraceLog;
63
using yb::debug::TraceResultBuffer;
64
65
using namespace std::placeholders;
66
67
enum Handler {
68
  kBeginMonitoring,
69
  kEndMonitoring,
70
  kCaptureMonitoring,
71
  kGetMonitoringStatus,
72
  kCategories,
73
  kBeginRecording,
74
  kGetBufferPercentFull,
75
  kEndRecording,
76
  kSimpleDump
77
};
78
79
namespace {
80
81
Status ParseBase64JsonRequest(const string& json_base64,
82
1
                              rapidjson::Document* doc) {
83
1
  string json_str;
84
1
  if (!Base64Unescape(json_base64, &json_str)) {
85
0
    return STATUS(InvalidArgument, "Invalid base64-encoded JSON");
86
0
  }
87
88
1
  doc->Parse<0>(json_str.c_str());
89
1
  if (!doc->IsObject()) {
90
0
    return STATUS(InvalidArgument, "Invalid JSON", json_str);
91
0
  }
92
1
  return Status::OK();
93
1
}
94
95
Status GetTracingOptions(const std::string& json_base64,
96
                       std::string* category_filter_string,
97
1
                       int* tracing_options) {
98
1
  rapidjson::Document doc;
99
1
  RETURN_NOT_OK(ParseBase64JsonRequest(json_base64, &doc));
100
101
1
  bool use_continuous_tracing = false;
102
1
  bool use_sampling = false;
103
104
1
  if (!doc.HasMember("categoryFilter") ||
105
1
      !doc["categoryFilter"].IsString()) {
106
0
    return STATUS(InvalidArgument, "missing categoryFilter");
107
0
  }
108
1
  *category_filter_string = doc["categoryFilter"].GetString();
109
110
1
  if (doc.HasMember("useContinuousTracing") &&
111
1
      doc["useContinuousTracing"].IsBool()) {
112
0
    use_continuous_tracing = doc["useContinuousTracing"].GetBool();
113
0
  }
114
115
1
  if (doc.HasMember("useSampling") &&
116
1
      doc["useSampling"].IsBool()) {
117
0
    use_sampling = doc["useSampling"].GetBool();
118
0
  }
119
120
1
  *tracing_options = 0;
121
1
  if (use_sampling)
122
0
    *tracing_options |= TraceLog::ENABLE_SAMPLING;
123
1
  if (use_continuous_tracing)
124
0
    *tracing_options |= TraceLog::RECORD_CONTINUOUSLY;
125
1
  return Status::OK();
126
1
}
127
128
Status BeginRecording(const Webserver::WebRequest& req,
129
1
                      TraceLog::Mode mode) {
130
1
  string filter_str;
131
1
  int options = 0;
132
1
  RETURN_NOT_OK(GetTracingOptions(req.query_string, &filter_str, &options));
133
134
1
  yb::debug::TraceLog::GetInstance()->SetEnabled(
135
1
    CategoryFilter(filter_str),
136
1
    mode,
137
1
    static_cast<TraceLog::Options>(options));
138
1
  return Status::OK();
139
1
}
140
141
142
Status EndRecording(const Webserver::WebRequest& req,
143
1
                    Webserver::WebResponse* resp) {
144
1
  std::stringstream *output = &resp->output;
145
1
  TraceLog* tl = TraceLog::GetInstance();
146
1
  tl->SetDisabled();
147
1
  *output << TraceResultBuffer::FlushTraceLogToString();
148
1
  return Status::OK();
149
1
}
150
151
0
Status CaptureMonitoring(stringstream* output) {
152
0
  TraceLog* tl = TraceLog::GetInstance();
153
0
  if (!tl->IsEnabled()) {
154
0
    return STATUS(IllegalState, "monitoring not enabled");
155
0
  }
156
0
  *output << TraceResultBuffer::FlushTraceLogToStringButLeaveBufferIntact();
157
0
  return Status::OK();
158
0
}
159
160
1
void GetCategories(stringstream* output) {
161
1
  vector<string> groups;
162
1
  yb::debug::TraceLog::GetInstance()->GetKnownCategoryGroups(&groups);
163
1
  JsonWriter j(output, JsonWriter::COMPACT);
164
1
  j.StartArray();
165
10
  for (const string& g : groups) {
166
10
    j.String(g);
167
10
  }
168
1
  j.EndArray();
169
1
}
170
171
0
void GetMonitoringStatus(stringstream* output) {
172
0
  TraceLog* tl = TraceLog::GetInstance();
173
0
  bool is_monitoring = tl->IsEnabled();
174
0
  std::string category_filter = tl->GetCurrentCategoryFilter().ToString();
175
0
  int options = static_cast<int>(tl->trace_options());
176
177
0
  stringstream json_out;
178
0
  JsonWriter j(&json_out, JsonWriter::COMPACT);
179
0
  j.StartObject();
180
181
0
  j.String("isMonitoring");
182
0
  j.Bool(is_monitoring);
183
184
0
  j.String("categoryFilter");
185
0
  j.String(category_filter);
186
187
0
  j.String("useContinuousTracing");
188
0
  j.Bool((options & TraceLog::RECORD_CONTINUOUSLY) != 0);
189
190
0
  j.String("useSampling");
191
0
  j.Bool((options & TraceLog::ENABLE_SAMPLING) != 0);
192
193
0
  j.EndObject();
194
195
0
  string encoded;
196
0
  strings::Base64Escape(json_out.str(), &encoded);
197
0
  *output << encoded;
198
0
}
199
200
void HandleTraceJsonPage(const Webserver::ArgumentMap &args,
201
0
                         std::stringstream* output) {
202
0
  TraceLog* tl = TraceLog::GetInstance();
203
0
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
204
0
                 TraceLog::RECORDING_MODE,
205
0
                 TraceLog::RECORD_CONTINUOUSLY);
206
0
  SleepFor(MonoDelta::FromSeconds(10));
207
0
  tl->SetDisabled();
208
209
0
  *output << TraceResultBuffer::FlushTraceLogToString();
210
0
}
211
212
Status DoHandleRequest(Handler handler,
213
                       const Webserver::WebRequest& req,
214
4
                       Webserver::WebResponse* resp) {
215
4
  std::stringstream *output = &resp->output;
216
0
  VLOG(2) << "Tracing request type=" << handler << ": " << req.query_string;
217
218
4
  switch (handler) {
219
0
    case kBeginMonitoring:
220
0
      RETURN_NOT_OK(BeginRecording(req, TraceLog::MONITORING_MODE));
221
0
      break;
222
0
    case kCaptureMonitoring:
223
0
      RETURN_NOT_OK(CaptureMonitoring(output));
224
0
      break;
225
0
    case kGetMonitoringStatus:
226
0
      GetMonitoringStatus(output);
227
0
      break;
228
1
    case kCategories:
229
1
      GetCategories(output);
230
1
      break;
231
1
    case kBeginRecording:
232
1
      RETURN_NOT_OK(BeginRecording(req, TraceLog::RECORDING_MODE));
233
1
      break;
234
1
    case kGetBufferPercentFull:
235
1
      *output << TraceLog::GetInstance()->GetBufferPercentFull();
236
1
      break;
237
0
    case kEndMonitoring:
238
1
    case kEndRecording:
239
1
      RETURN_NOT_OK(EndRecording(req, resp));
240
1
      break;
241
0
    case kSimpleDump:
242
0
      HandleTraceJsonPage(req.parsed_args, output);
243
0
      break;
244
4
  }
245
246
4
  return Status::OK();
247
4
}
248
249
250
void HandleRequest(Handler handler,
251
                   const Webserver::WebRequest& req,
252
4
                   Webserver::WebResponse* resp) {
253
4
  std::stringstream *output = &resp->output;
254
4
  Status s = DoHandleRequest(handler, req, resp);
255
4
  if (!s.ok()) {
256
0
    LOG(WARNING) << "Tracing error for handler " << handler << ": "
257
0
                 << s.ToString();
258
    // The trace-viewer JS expects '##ERROR##' to indicate that an error
259
    // occurred. TODO: change the JS to bubble up the actual error message
260
    // to the user.
261
0
    *output << "##ERROR##";
262
0
  }
263
4
}
264
} // anonymous namespace
265
266
267
17.1k
void TracingPathHandlers::RegisterHandlers(Webserver* server) {
268
  // All of the tracing-related hand
269
17.1k
  std::map<string, Handler> handlers = {
270
17.1k
    { "/tracing/json/begin_monitoring", kBeginMonitoring },
271
17.1k
    { "/tracing/json/end_monitoring", kEndMonitoring },
272
17.1k
    { "/tracing/json/capture_monitoring", kCaptureMonitoring },
273
17.1k
    { "/tracing/json/get_monitoring_status", kGetMonitoringStatus },
274
17.1k
    { "/tracing/json/categories", kCategories },
275
17.1k
    { "/tracing/json/begin_recording", kBeginRecording },
276
17.1k
    { "/tracing/json/get_buffer_percent_full", kGetBufferPercentFull },
277
17.1k
    { "/tracing/json/end_recording", kEndRecording },
278
17.1k
    { "/tracing/json/simple_dump", kSimpleDump } };
279
280
17.1k
  typedef pair<string, Handler> HandlerPair;
281
154k
  for (const HandlerPair e : handlers) {
282
154k
    server->RegisterPathHandler(
283
154k
        e.first, "", std::bind(&HandleRequest, e.second, _1, _2), false /* styled */,
284
154k
        false /* is_on_nav_bar */);
285
154k
  }
286
17.1k
}
287
288
} // namespace server
289
} // namespace yb