Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use runtime key in duration filter. #28

Merged
merged 5 commits into from
Aug 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions docs/configuration/http_conn_man/access_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ Status code
"filter": {
"type": "status_code",
"op": "...",
"value": "..."
"value": "...",
"runtime_key": "..."
}
}

Expand All @@ -142,7 +143,10 @@ op
*(required, string)* Comparison operator. Currently *>=* is the only supported operator.

value
*(required, integer)* The value to compare against.
*(required, integer)* Default value to compare against if runtime value is not available.

runtime_key
*(optional, string)* Runtime key to get value for comparision. This value is used if defined.

Duration
^^^^^^^^
Expand All @@ -153,7 +157,8 @@ Duration
"filter": {
"type": "duration",
"op": "..",
"value": "..."
"value": "...",
"runtime_key": "..."
}
}

Expand All @@ -163,7 +168,11 @@ op
*(required, string)* Comparison operator. Currently *>=* is the only supported operator.

value
*(required, integer)* The value to compare against.
*(required, integer)* Default value to compare against if runtime values is not available.

runtime_key
*(optional, string)* Runtime key to get value for comparision. This value is used if defined.


Not health check
^^^^^^^^^^^^^^^^
Expand Down
21 changes: 16 additions & 5 deletions source/common/http/access_log_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
namespace Http {
namespace AccessLog {

FilterImpl::FilterImpl(Json::Object& json) : value_(json.getInteger("value")) {
FilterImpl::FilterImpl(Json::Object& json, Runtime::Loader& runtime)
: value_(json.getInteger("value")), runtime_(runtime) {
std::string op = json.getString("op");
if (op == ">=") {
op_ = FilterOperation::GreaterEqual;
Expand All @@ -28,14 +29,24 @@ FilterImpl::FilterImpl(Json::Object& json) : value_(json.getInteger("value")) {
} else {
throw EnvoyException(fmt::format("invalid access log filter op '{}'", op));
}

if (json.hasObject("runtime_key")) {
runtime_key_.value(json.getString("runtime_key"));
}
}

bool FilterImpl::compareAgainstValue(uint64_t lhs) {
uint64_t value = value_;

if (runtime_key_.valid()) {
value = runtime_.snapshot().getInteger(runtime_key_.value(), value);
}

switch (op_) {
case FilterOperation::GreaterEqual:
return lhs >= value_;
return lhs >= value;
case FilterOperation::Equal:
return lhs == value_;
return lhs == value;
}

NOT_IMPLEMENTED;
Expand All @@ -44,9 +55,9 @@ bool FilterImpl::compareAgainstValue(uint64_t lhs) {
FilterPtr FilterImpl::fromJson(Json::Object& json, Runtime::Loader& runtime) {
std::string type = json.getString("type");
if (type == "status_code") {
return FilterPtr{new StatusCodeFilter(json)};
return FilterPtr{new StatusCodeFilter(json, runtime)};
} else if (type == "duration") {
return FilterPtr{new DurationFilter(json)};
return FilterPtr{new DurationFilter(json, runtime)};
} else if (type == "runtime") {
return FilterPtr{new RuntimeFilter(json, runtime)};
} else if (type == "logical_or") {
Expand Down
8 changes: 5 additions & 3 deletions source/common/http/access_log_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,22 @@ class FilterImpl : public Filter {
static FilterPtr fromJson(Json::Object& json, Runtime::Loader& runtime);

protected:
FilterImpl(Json::Object& json);
FilterImpl(Json::Object& json, Runtime::Loader& runtime);

bool compareAgainstValue(uint64_t lhs);

FilterOperation op_;
uint64_t value_;
Runtime::Loader& runtime_;
Optional<std::string> runtime_key_;
};

/**
* Filter on response status code.
*/
class StatusCodeFilter : public FilterImpl {
public:
StatusCodeFilter(Json::Object& json) : FilterImpl(json) {}
StatusCodeFilter(Json::Object& json, Runtime::Loader& runtime) : FilterImpl(json, runtime) {}

// Http::AccessLog::Filter
bool evaluate(const RequestInfo& info, const HeaderMap& request_headers) override;
Expand All @@ -49,7 +51,7 @@ class StatusCodeFilter : public FilterImpl {
*/
class DurationFilter : public FilterImpl {
public:
DurationFilter(Json::Object& json) : FilterImpl(json) {}
DurationFilter(Json::Object& json, Runtime::Loader& runtime) : FilterImpl(json, runtime) {}

// Http::AccessLog::Filter
bool evaluate(const RequestInfo& info, const HeaderMap& request_headers) override;
Expand Down
56 changes: 56 additions & 0 deletions test/common/http/access_log_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -581,5 +581,61 @@ TEST_F(AccessLogImplTest, multipleOperators) {
}
}

TEST(AccessLogFilterTest, DurationWithRuntimeKey) {
std::string filter_json = R"EOF(
{
"filter": {"type": "duration", "op": ">=", "value": 1000000, "runtime_key": "key"}
}
)EOF";

Json::StringLoader loader(filter_json);
NiceMock<Runtime::MockLoader> runtime;

Json::Object filter_object = loader.getObject("filter");
DurationFilter filter(filter_object, runtime);
HeaderMapImpl request_headers{{":method", "GET"}, {":path", "/"}};
TestRequestInfo request_info;

request_info.duration_ = 100;

EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(1));
EXPECT_TRUE(filter.evaluate(request_info, request_headers));

EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(1000));
EXPECT_FALSE(filter.evaluate(request_info, request_headers));

request_info.duration_ = 100000001;
EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(100000000));
EXPECT_TRUE(filter.evaluate(request_info, request_headers));

request_info.duration_ = 10;
EXPECT_CALL(runtime.snapshot_, getInteger("key", 1000000)).WillOnce(Return(100000000));
EXPECT_FALSE(filter.evaluate(request_info, request_headers));
}

TEST(AccessLogFilterTest, StatusCodeWithRuntimeKey) {
std::string filter_json = R"EOF(
{
"filter": {"type": "status_code", "op": ">=", "value": 300, "runtime_key": "key"}
}
)EOF";

Json::StringLoader loader(filter_json);
NiceMock<Runtime::MockLoader> runtime;

Json::Object filter_object = loader.getObject("filter");
StatusCodeFilter filter(filter_object, runtime);

HeaderMapImpl request_headers{{":method", "GET"}, {":path", "/"}};
TestRequestInfo info;

info.response_code_.value(400);
EXPECT_CALL(runtime.snapshot_, getInteger("key", 300)).WillOnce(Return(350));
EXPECT_TRUE(filter.evaluate(info, request_headers));

EXPECT_CALL(runtime.snapshot_, getInteger("key", 300)).WillOnce(Return(500));
EXPECT_FALSE(filter.evaluate(info, request_headers));
}

} // AccessLog
} // Http