1
#include "source/server/admin/profiling_handler.h"
2

            
3
#include "source/common/profiler/profiler.h"
4
#include "source/server/admin/utils.h"
5

            
6
namespace Envoy {
7
namespace Server {
8

            
9
10735
ProfilingHandler::ProfilingHandler(const std::string& profile_path) : profile_path_(profile_path) {}
10

            
11
Http::Code ProfilingHandler::handlerCpuProfiler(Http::ResponseHeaderMap&,
12
                                                Buffer::Instance& response,
13
12
                                                AdminStream& admin_stream) {
14
12
  Http::Utility::QueryParamsMulti query_params = admin_stream.queryParams();
15
12
  const auto enableVal = query_params.getFirstValue("enable");
16
12
  if (query_params.data().size() != 1 || !enableVal.has_value() ||
17
12
      (enableVal.value() != "y" && enableVal.value() != "n")) {
18
3
    response.add("?enable=<y|n>\n");
19
3
    return Http::Code::BadRequest;
20
3
  }
21

            
22
9
  bool enable = enableVal.value() == "y";
23
9
  if (enable && !Profiler::Cpu::profilerEnabled()) {
24
5
    if (!Profiler::Cpu::startProfiler(profile_path_)) {
25
1
      response.add("failure to start the profiler");
26
1
      return Http::Code::InternalServerError;
27
1
    }
28

            
29
5
  } else if (!enable && Profiler::Cpu::profilerEnabled()) {
30
4
    Profiler::Cpu::stopProfiler();
31
4
  }
32

            
33
8
  response.add("OK\n");
34
8
  return Http::Code::OK;
35
9
}
36

            
37
Http::Code ProfilingHandler::handlerHeapProfiler(Http::ResponseHeaderMap&,
38
                                                 Buffer::Instance& response,
39
6
                                                 AdminStream& admin_stream) {
40
6
  if (!Profiler::Heap::profilerEnabled()) {
41
    response.add("The current build does not support heap profiler");
42
    return Http::Code::NotImplemented;
43
  }
44

            
45
6
  Http::Utility::QueryParamsMulti query_params = admin_stream.queryParams();
46
6
  const auto enableVal = query_params.getFirstValue("enable");
47
6
  if (query_params.data().size() != 1 || !enableVal.has_value() ||
48
6
      (enableVal.value() != "y" && enableVal.value() != "n")) {
49
    response.add("?enable=<y|n>\n");
50
    return Http::Code::BadRequest;
51
  }
52

            
53
6
  Http::Code res = Http::Code::OK;
54
6
  bool enable = enableVal.value() == "y";
55
6
  if (enable) {
56
3
    if (Profiler::Heap::isProfilerStarted()) {
57
1
      response.add("Fail to start heap profiler: already started");
58
1
      res = Http::Code::BadRequest;
59
2
    } else if (!Profiler::Heap::startProfiler(profile_path_)) {
60
      response.add("Fail to start the heap profiler");
61
      res = Http::Code::InternalServerError;
62
2
    } else {
63
2
      response.add("Starting heap profiler");
64
2
      res = Http::Code::OK;
65
2
    }
66
3
  } else {
67
    // !enable
68
3
    if (!Profiler::Heap::isProfilerStarted()) {
69
1
      response.add("Fail to stop heap profiler: not started");
70
1
      res = Http::Code::BadRequest;
71
2
    } else {
72
2
      Profiler::Heap::stopProfiler();
73
2
      response.add(
74
2
          fmt::format("Heap profiler stopped and data written to {}. See "
75
2
                      "http://goog-perftools.sourceforge.net/doc/heap_profiler.html for details.",
76
2
                      profile_path_));
77
2
      res = Http::Code::OK;
78
2
    }
79
3
  }
80
6
  return res;
81
6
}
82

            
83
Http::Code TcmallocProfilingHandler::handlerHeapDump(Http::ResponseHeaderMap&,
84
1
                                                     Buffer::Instance& response, AdminStream&) {
85
1
  auto dump_result = Profiler::TcmallocProfiler::tcmallocHeapProfile();
86

            
87
1
  if (dump_result.ok()) {
88
    response.add(dump_result.value());
89
    return Http::Code::OK;
90
  }
91

            
92
1
  response.add(dump_result.status().message());
93
1
  return Http::Code::NotImplemented;
94
1
}
95

            
96
Http::Code TcmallocProfilingHandler::handlerAllocationProfiler(Http::ResponseHeaderMap&,
97
                                                               Buffer::Instance& response,
98
3
                                                               AdminStream& admin_stream) {
99
3
  Http::Utility::QueryParamsMulti query_params = admin_stream.queryParams();
100
3
  const auto enableVal = query_params.getFirstValue("enable");
101
3
  if (query_params.data().size() != 1 || !enableVal.has_value() ||
102
3
      (enableVal.value() != "y" && enableVal.value() != "n")) {
103
1
    response.add("?enable=<y|n>\n");
104
1
    return Http::Code::BadRequest;
105
1
  }
106
2
  const bool enable = enableVal.value() == "y";
107
2
  if (enable) {
108
1
    const auto started = Profiler::TcmallocProfiler::startAllocationProfile();
109
1
    if (!started.ok()) {
110
1
      response.add(started.message());
111
1
      return Http::Code::BadRequest;
112
1
    }
113
    response.add("OK\n");
114
    return Http::Code::OK;
115
1
  }
116
1
  const auto profile = Profiler::TcmallocProfiler::stopAllocationProfile();
117
1
  if (!profile.ok()) {
118
1
    response.add(profile.status().message());
119
1
    return Http::Code::BadRequest;
120
1
  }
121
  response.add(profile.value());
122
  return Http::Code::OK;
123
1
}
124

            
125
} // namespace Server
126
} // namespace Envoy