@@ -14,8 +14,10 @@ limitations under the License.
14
14
==============================================================================*/
15
15
16
16
#include < cstdint>
17
+ #include < memory>
17
18
18
19
#include " absl/strings/str_cat.h"
20
+ #include " absl/strings/str_format.h"
19
21
#include " absl/strings/string_view.h"
20
22
#include " re2/re2.h"
21
23
#include " tensorflow/core/platform/env.h"
@@ -26,6 +28,7 @@ limitations under the License.
26
28
#include " tensorflow_serving/util/net_http/server/public/httpserver.h"
27
29
#include " tensorflow_serving/util/net_http/server/public/response_code_enum.h"
28
30
#include " tensorflow_serving/util/net_http/server/public/server_request_interface.h"
31
+ #include " tensorflow_serving/util/prometheus_exporter.h"
29
32
#include " tensorflow_serving/util/threadpool_executor.h"
30
33
31
34
namespace tensorflow {
@@ -79,6 +82,35 @@ net_http::HTTPStatusCode ToHTTPStatusCode(const Status& status) {
79
82
}
80
83
}
81
84
85
+ void ProcessPrometheusRequest (PrometheusExporter* exporter,
86
+ const PrometheusConfig& prometheus_config,
87
+ net_http::ServerRequestInterface* req) {
88
+ std::vector<std::pair<string, string>> headers;
89
+ headers.push_back ({" Content-Type" , " text/plain" });
90
+ string output;
91
+ Status status;
92
+ // Check if url matches the path.
93
+ if (req->uri_path () != prometheus_config.path ()) {
94
+ output = absl::StrFormat (" Unexpected path: %s. Should be %s" ,
95
+ req->uri_path (), prometheus_config.path ());
96
+ status = Status (error::Code::INVALID_ARGUMENT, output);
97
+ } else {
98
+ status = exporter->GeneratePage (&output);
99
+ }
100
+ const net_http::HTTPStatusCode http_status = ToHTTPStatusCode (status);
101
+ // Note: we add headers+output for non successful status too, in case the
102
+ // output contains details about the error (e.g. error messages).
103
+ for (const auto & kv : headers) {
104
+ req->OverwriteResponseHeader (kv.first , kv.second );
105
+ }
106
+ req->WriteResponseString (output);
107
+ if (http_status != net_http::HTTPStatusCode::OK) {
108
+ VLOG (1 ) << " Error Processing prometheus metrics request. Error: "
109
+ << status.ToString ();
110
+ }
111
+ req->ReplyWithStatus (http_status);
112
+ }
113
+
82
114
class RequestExecutor final : public net_http::EventExecutor {
83
115
public:
84
116
explicit RequestExecutor (int num_threads)
@@ -147,7 +179,8 @@ class RestApiRequestDispatcher {
147
179
} // namespace
148
180
149
181
std::unique_ptr<net_http::HTTPServerInterface> CreateAndStartHttpServer (
150
- int port, int num_threads, int timeout_in_ms, ServerCore* core) {
182
+ int port, int num_threads, int timeout_in_ms,
183
+ const MonitoringConfig& monitoring_config, ServerCore* core) {
151
184
auto options = absl::make_unique<net_http::ServerOptions>();
152
185
options->AddPort (static_cast <uint32_t >(port));
153
186
options->SetExecutor (absl::make_unique<RequestExecutor>(num_threads));
@@ -157,6 +190,20 @@ std::unique_ptr<net_http::HTTPServerInterface> CreateAndStartHttpServer(
157
190
return nullptr ;
158
191
}
159
192
193
+ // Register handler for prometheus metric endpoint.
194
+ if (monitoring_config.prometheus_config ().enable ()) {
195
+ std::shared_ptr<PrometheusExporter> exporter =
196
+ std::make_shared<PrometheusExporter>();
197
+ net_http::RequestHandlerOptions prometheus_request_options;
198
+ PrometheusConfig prometheus_config = monitoring_config.prometheus_config ();
199
+ server->RegisterRequestHandler (
200
+ monitoring_config.prometheus_config ().path (),
201
+ [exporter, prometheus_config](net_http::ServerRequestInterface* req) {
202
+ ProcessPrometheusRequest (exporter.get (), prometheus_config, req);
203
+ },
204
+ prometheus_request_options);
205
+ }
206
+
160
207
std::shared_ptr<RestApiRequestDispatcher> dispatcher =
161
208
std::make_shared<RestApiRequestDispatcher>(timeout_in_ms, core);
162
209
net_http::RequestHandlerOptions handler_options;
0 commit comments