Skip to content
This repository has been archived by the owner on Jun 23, 2022. It is now read-only.

Commit

Permalink
feat: add http interface to get perf counter info (#349)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhao liwei authored and Wu Tao committed Dec 10, 2019
1 parent fdb19b1 commit daff2f9
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/dsn/perf_counter/perf_counters.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class perf_counters : public utils::singleton<perf_counters>
///
bool remove_counter(const char *full_name);

perf_counter_ptr get_counter(const std::string &full_name);

struct counter_snapshot
{
double value{0.0};
Expand Down
10 changes: 10 additions & 0 deletions src/core/perf_counter/perf_counters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ bool perf_counters::remove_counter(const char *full_name)
return true;
}

perf_counter_ptr perf_counters::get_counter(const std::string &full_name)
{
utils::auto_read_lock l(_lock);
auto it = _counters.find(full_name);
if (it != _counters.end())
return it->second.counter;

return nullptr;
}

perf_counter *perf_counters::new_counter(const char *app,
const char *section,
const char *name,
Expand Down
30 changes: 30 additions & 0 deletions src/core/tests/perf_counters_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,33 @@ TEST(perf_counters_test, query_snapshot_by_regexp)
printf("got timestamp: %s\n", info.timestamp_str.c_str());
ASSERT_TRUE(info.counters.empty());
}

TEST(perf_counters_test, get_by_fullname)
{
struct test_case
{
const char *app;
const char *section;
const char *name;
dsn_perf_counter_type_t type;
const char *dsptr;
bool create;
} tests[] = {{"replica", "eon", "get_by_fullname1", COUNTER_TYPE_NUMBER, "pf1", false},
{"replica", "eon", "get_by_fullname2", COUNTER_TYPE_NUMBER, "pf2", true}};

for (auto test : tests) {
// precondition: make sure the perf counter doesn't exist
std::string perf_counter_name;
perf_counter::build_full_name(test.app, test.section, test.name, perf_counter_name);
perf_counters::instance().remove_counter(perf_counter_name.c_str());

if (test.create) {
// create perf counter
perf_counter_wrapper counter;
counter.init_global_counter(test.app, test.section, test.name, test.type, test.dsptr);
ASSERT_NE(nullptr, perf_counters::instance().get_counter(perf_counter_name));
} else {
ASSERT_EQ(nullptr, perf_counters::instance().get_counter(perf_counter_name));
}
}
}
3 changes: 3 additions & 0 deletions src/dist/http/http_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "http_message_parser.h"
#include "root_http_service.h"
#include "pprof_http_service.h"
#include "perf_counter_http_service.h"

namespace dsn {

Expand Down Expand Up @@ -44,6 +45,8 @@ http_server::http_server() : serverlet<http_server>("http_server")
#ifdef DSN_ENABLE_GPERF
add_service(new pprof_http_service());
#endif // DSN_ENABLE_GPERF

add_service(new perf_counter_http_service());
}

void http_server::serve(message_ex *msg)
Expand Down
45 changes: 45 additions & 0 deletions src/dist/http/perf_counter_http_service.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <dsn/utility/output_utils.h>
#include "perf_counter_http_service.h"

namespace dsn {

void perf_counter_http_service::get_perf_counter_handler(const http_request &req,
http_response &resp)
{
std::string perf_counter_name;
for (const auto &p : req.query_args) {
if ("name" == p.first) {
perf_counter_name = p.second;
} else {
resp.status_code = http_status_code::bad_request;
return;
}
}

// get perf counter by perf counter name
perf_counter_ptr perf_counter = perf_counters::instance().get_counter(perf_counter_name);

// insert perf counter info into table printer
dsn::utils::table_printer tp;
if (perf_counter) {
tp.add_row_name_and_data("name", perf_counter_name);
if (COUNTER_TYPE_NUMBER_PERCENTILES == perf_counter->type()) {
tp.add_row_name_and_data("p99", perf_counter->get_percentile(COUNTER_PERCENTILE_99));
tp.add_row_name_and_data("p999", perf_counter->get_percentile(COUNTER_PERCENTILE_999));
} else {
tp.add_row_name_and_data("value", perf_counter->get_value());
}
tp.add_row_name_and_data("type", dsn_counter_type_to_string(perf_counter->type()));
tp.add_row_name_and_data("description", perf_counter->dsptr());
}

std::ostringstream out;
tp.output(out, dsn::utils::table_printer::output_format::kJsonCompact);
resp.body = out.str();
resp.status_code = http_status_code::ok;
}
} // namespace dsn
28 changes: 28 additions & 0 deletions src/dist/http/perf_counter_http_service.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#pragma once

#include <dsn/tool-api/http_server.h>

namespace dsn {

class perf_counter_http_service : public http_service
{
public:
perf_counter_http_service()
{
// GET ip:port/perfCounter?name={perf_counter_name}
register_handler("",
std::bind(&perf_counter_http_service::get_perf_counter_handler,
this,
std::placeholders::_1,
std::placeholders::_2));
}

std::string path() const override { return "perfCounter"; }

void get_perf_counter_handler(const http_request &req, http_response &resp);
};
} // namespace dsn
65 changes: 65 additions & 0 deletions src/dist/http/test/perf_counter_http_service_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) 2018, Xiaomi, Inc. All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#include <gtest/gtest.h>
#include <dsn/perf_counter/perf_counters.h>
#include <dsn/tool-api/http_server.h>
#include <dist/http/perf_counter_http_service.h>

namespace dsn {

class perf_counter_http_service_test : public testing::Test
{
public:
perf_counter_http_service _perf_counter_http_service;
};

TEST_F(perf_counter_http_service_test, get_perf_counter)
{
struct test_case
{
const char *app;
const char *section;
const char *name;
dsn_perf_counter_type_t type;
const char *description;
} tests[] = {
{"replica", "http", "number", COUNTER_TYPE_NUMBER, "number type"},
{"replica", "http", "volatile", COUNTER_TYPE_VOLATILE_NUMBER, "volatile type"},
{"replica", "http", "rate", COUNTER_TYPE_RATE, "rate type"},
{"replica", "http", "percentline", COUNTER_TYPE_NUMBER_PERCENTILES, "percentline type"}};

for (auto test : tests) {
// create perf counter
perf_counter_wrapper counter;
counter.init_global_counter(test.app, test.section, test.name, test.type, test.description);

std::string perf_counter_name;
perf_counter::build_full_name(test.app, test.section, test.name, perf_counter_name);

// get perf counter info through the http interface
http_request fake_req;
http_response fake_resp;
fake_req.query_args.emplace("name", perf_counter_name);
_perf_counter_http_service.get_perf_counter_handler(fake_req, fake_resp);

// get fake json based on the perf counter info which is getting above
std::string fake_json;
if (COUNTER_TYPE_NUMBER_PERCENTILES == test.type) {
fake_json = R"({"name":")" + perf_counter_name + R"(",)" +
R"("p99":"0.00","p999":"0.00",)" +
R"("type":")" + dsn_counter_type_to_string(test.type) + R"(",)" +
R"("description":")" + test.description + R"("})" + "\n";
} else {
fake_json = R"({"name":")" + perf_counter_name + R"(",)" +
R"("value":"0.00",)" +
R"("type":")" + dsn_counter_type_to_string(test.type) + R"(",)" +
R"("description":")" + test.description + R"("})" + "\n";
}

ASSERT_EQ(fake_resp.status_code, http_status_code::ok);
ASSERT_EQ(fake_resp.body, fake_json);
}
}
} // namespace dsn

0 comments on commit daff2f9

Please sign in to comment.