-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add Couch Stats Resource Tracker (CSRT) #5491
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
Changes from all commits
175a76d
d99c812
922b3f8
375ec28
ada453e
9aadac4
1421a50
cba2e9c
020743f
975818e
a8dd0d6
f280d1b
ae419d6
57c19cd
2bfefd4
089f02d
a999033
e070513
befdfcb
11f9755
6fd6a29
fbd7455
04c588d
1063b8a
f6a7bf6
d973007
7211093
a7f3342
b58e04a
c9371ee
06da5f2
c41ac4f
e4198ed
720649d
0a6c556
7b96f89
3e4736a
7de1d96
e41e441
3074f77
5919cc2
39c4675
c489a61
9735ca7
6224242
97329a7
5166762
45a94e5
24d5626
6533bc7
7497f09
9016bd1
1db2e8d
73a5893
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1119,3 +1119,42 @@ url = {{nouveau_url}} | |
;mem3_shards = true | ||
;nouveau_index_manager = true | ||
;dreyfus_index_manager = true | ||
|
||
; Couch Stats Resource Tracker (CSRT) | ||
[csrt] | ||
enable = true | ||
enable_init_p = true | ||
enable_reporting = true | ||
;enable = false | ||
;enable_init_p = false | ||
;enable_reporting = false | ||
;enable_rpc_reporting = false | ||
|
||
; Truncate reports to not include zero values for counter fields | ||
;should_truncate_reports = true | ||
|
||
; CSRT Rexi Server RPC Worker Spawn Tracking | ||
; Enable these to enable additional metrics for RPC worker spawn rates | ||
; measuring how often RPC workers are spawned by way of rexi_server:init_p. | ||
; Mod and Function are separated by double underscores. | ||
[csrt.init_p] | ||
fabric_rpc__all_docs = true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of a double underscore, would a more traditional erlang colon work: |
||
fabric_rpc__changes = true | ||
fabric_rpc__map_view = true | ||
fabric_rpc__reduce_view = true | ||
fabric_rpc__get_all_security = true | ||
fabric_rpc__open_doc = true | ||
fabric_rpc__update_docs = true | ||
fabric_rpc__open_shard = true | ||
Comment on lines
+1142
to
+1148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice, it would be great to see detailed reports on what these workers are doing! |
||
|
||
; CSRT dbname matchers | ||
; Given a dbname and a positive integer, this will enable an IO matcher | ||
; against the provided db for any requests that induce IO in quantities | ||
; greater than the provided threshold on any one of: ioq_calls, rows_read | ||
; docs_read, get_kp_node, get_kv_node, or changes_processed. | ||
; | ||
[csrt_logger.dbnames_io] | ||
; foo = 100 | ||
; _dbs = 123 | ||
; _users = 234 | ||
; foo/bar = 200 |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -20,6 +20,7 @@ | |||||||||||||||||||||||||||||||
handle_replicate_req/1, | ||||||||||||||||||||||||||||||||
handle_reload_query_servers_req/1, | ||||||||||||||||||||||||||||||||
handle_task_status_req/1, | ||||||||||||||||||||||||||||||||
handle_resource_status_req/1, | ||||||||||||||||||||||||||||||||
handle_up_req/1, | ||||||||||||||||||||||||||||||||
handle_utils_dir_req/1, | ||||||||||||||||||||||||||||||||
handle_utils_dir_req/2, | ||||||||||||||||||||||||||||||||
|
@@ -219,6 +220,112 @@ handle_task_status_req(#httpd{method = 'GET'} = Req) -> | |||||||||||||||||||||||||||||||
handle_task_status_req(Req) -> | ||||||||||||||||||||||||||||||||
send_method_not_allowed(Req, "GET,HEAD"). | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
handle_resource_status_req(#httpd{method = 'POST'} = Req) -> | ||||||||||||||||||||||||||||||||
ok = chttpd:verify_is_server_admin(Req), | ||||||||||||||||||||||||||||||||
chttpd:validate_ctype(Req, "application/json"), | ||||||||||||||||||||||||||||||||
{Props} = chttpd:json_body_obj(Req), | ||||||||||||||||||||||||||||||||
Action = proplists:get_value(<<"action">>, Props), | ||||||||||||||||||||||||||||||||
Key = proplists:get_value(<<"key">>, Props), | ||||||||||||||||||||||||||||||||
Val = proplists:get_value(<<"val">>, Props), | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
CountBy = fun csrt:count_by/1, | ||||||||||||||||||||||||||||||||
GroupBy = fun csrt:group_by/2, | ||||||||||||||||||||||||||||||||
SortedBy1 = fun csrt:sorted_by/1, | ||||||||||||||||||||||||||||||||
SortedBy2 = fun csrt:sorted_by/2, | ||||||||||||||||||||||||||||||||
ConvertEle = fun erlang:binary_to_existing_atom/1, | ||||||||||||||||||||||||||||||||
ConvertList = fun(L) -> [ConvertEle(E) || E <- L] end, | ||||||||||||||||||||||||||||||||
ToJson = fun csrt_util:to_json/1, | ||||||||||||||||||||||||||||||||
JsonKeys = fun(PL) -> [[ToJson(K), V] || {K, V} <- PL] end, | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Fun = | ||||||||||||||||||||||||||||||||
case {Action, Key, Val} of | ||||||||||||||||||||||||||||||||
{<<"count_by">>, Keys, undefined} when is_list(Keys) -> | ||||||||||||||||||||||||||||||||
Keys1 = [ConvertEle(K) || K <- Keys], | ||||||||||||||||||||||||||||||||
fun() -> CountBy(Keys1) end; | ||||||||||||||||||||||||||||||||
{<<"count_by">>, Key, undefined} -> | ||||||||||||||||||||||||||||||||
Key1 = ConvertEle(Key), | ||||||||||||||||||||||||||||||||
fun() -> CountBy(Key1) end; | ||||||||||||||||||||||||||||||||
{<<"group_by">>, Keys, Vals} when is_list(Keys) andalso is_list(Vals) -> | ||||||||||||||||||||||||||||||||
Keys1 = ConvertList(Keys), | ||||||||||||||||||||||||||||||||
Vals1 = ConvertList(Vals), | ||||||||||||||||||||||||||||||||
fun() -> GroupBy(Keys1, Vals1) end; | ||||||||||||||||||||||||||||||||
{<<"group_by">>, Key, Vals} when is_list(Vals) -> | ||||||||||||||||||||||||||||||||
Key1 = ConvertEle(Key), | ||||||||||||||||||||||||||||||||
Vals1 = ConvertList(Vals), | ||||||||||||||||||||||||||||||||
fun() -> GroupBy(Key1, Vals1) end; | ||||||||||||||||||||||||||||||||
{<<"group_by">>, Keys, Val} when is_list(Keys) -> | ||||||||||||||||||||||||||||||||
Keys1 = ConvertList(Keys), | ||||||||||||||||||||||||||||||||
Val1 = ConvertEle(Val), | ||||||||||||||||||||||||||||||||
fun() -> GroupBy(Keys1, Val1) end; | ||||||||||||||||||||||||||||||||
{<<"group_by">>, Key, Val} -> | ||||||||||||||||||||||||||||||||
Key1 = ConvertEle(Key), | ||||||||||||||||||||||||||||||||
Val1 = ConvertList(Val), | ||||||||||||||||||||||||||||||||
fun() -> GroupBy(Key1, Val1) end; | ||||||||||||||||||||||||||||||||
{<<"sorted_by">>, Key, undefined} -> | ||||||||||||||||||||||||||||||||
Key1 = ConvertEle(Key), | ||||||||||||||||||||||||||||||||
fun() -> JsonKeys(SortedBy1(Key1)) end; | ||||||||||||||||||||||||||||||||
{<<"sorted_by">>, Keys, undefined} when is_list(Keys) -> | ||||||||||||||||||||||||||||||||
Keys1 = [ConvertEle(K) || K <- Keys], | ||||||||||||||||||||||||||||||||
fun() -> JsonKeys(SortedBy1(Keys1)) end; | ||||||||||||||||||||||||||||||||
{<<"sorted_by">>, Keys, Vals} when is_list(Keys) andalso is_list(Vals) -> | ||||||||||||||||||||||||||||||||
Keys1 = ConvertList(Keys), | ||||||||||||||||||||||||||||||||
Vals1 = ConvertList(Vals), | ||||||||||||||||||||||||||||||||
fun() -> JsonKeys(SortedBy2(Keys1, Vals1)) end; | ||||||||||||||||||||||||||||||||
{<<"sorted_by">>, Key, Vals} when is_list(Vals) -> | ||||||||||||||||||||||||||||||||
Key1 = ConvertEle(Key), | ||||||||||||||||||||||||||||||||
Vals1 = ConvertList(Vals), | ||||||||||||||||||||||||||||||||
fun() -> JsonKeys(SortedBy2(Key1, Vals1)) end; | ||||||||||||||||||||||||||||||||
{<<"sorted_by">>, Keys, Val} when is_list(Keys) -> | ||||||||||||||||||||||||||||||||
Keys1 = ConvertList(Keys), | ||||||||||||||||||||||||||||||||
Val1 = ConvertEle(Val), | ||||||||||||||||||||||||||||||||
fun() -> JsonKeys(SortedBy2(Keys1, Val1)) end; | ||||||||||||||||||||||||||||||||
{<<"sorted_by">>, Key, Val} -> | ||||||||||||||||||||||||||||||||
Key1 = ConvertEle(Key), | ||||||||||||||||||||||||||||||||
Val1 = ConvertList(Val), | ||||||||||||||||||||||||||||||||
fun() -> JsonKeys(SortedBy2(Key1, Val1)) end; | ||||||||||||||||||||||||||||||||
_ -> | ||||||||||||||||||||||||||||||||
throw({badrequest, invalid_resource_request}) | ||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Fun1 = fun() -> | ||||||||||||||||||||||||||||||||
case Fun() of | ||||||||||||||||||||||||||||||||
Map when is_map(Map) -> | ||||||||||||||||||||||||||||||||
{maps:fold( | ||||||||||||||||||||||||||||||||
fun | ||||||||||||||||||||||||||||||||
%% TODO: Skip 0 value entries? | ||||||||||||||||||||||||||||||||
(_K, 0, A) -> A; | ||||||||||||||||||||||||||||||||
(K, V, A) -> [{ToJson(K), V} | A] | ||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||
[], | ||||||||||||||||||||||||||||||||
Map | ||||||||||||||||||||||||||||||||
)}; | ||||||||||||||||||||||||||||||||
List when is_list(List) -> | ||||||||||||||||||||||||||||||||
List | ||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
{Resp, _Bad} = rpc:multicall(erlang, apply, [ | ||||||||||||||||||||||||||||||||
fun() -> | ||||||||||||||||||||||||||||||||
{node(), Fun1()} | ||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||
[] | ||||||||||||||||||||||||||||||||
]), | ||||||||||||||||||||||||||||||||
Comment on lines
+290
to
+312
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless absolutely necessary, it's not a good idea to pass function closures through the dist protocol. We've done that mistake with attachments in the past and had since removed it. It might be better to create a utility function, and do an See how we get active tasks for instance: couchdb/src/chttpd/src/chttpd_util.erl Lines 174 to 188 in c3789e9
|
||||||||||||||||||||||||||||||||
%%io:format("{CSRT}***** GOT RESP: ~p~n", [Resp]), | ||||||||||||||||||||||||||||||||
send_json(Req, {Resp}); | ||||||||||||||||||||||||||||||||
handle_resource_status_req(#httpd{method = 'GET'} = Req) -> | ||||||||||||||||||||||||||||||||
ok = chttpd:verify_is_server_admin(Req), | ||||||||||||||||||||||||||||||||
{Resp, Bad} = rpc:multicall(erlang, apply, [ | ||||||||||||||||||||||||||||||||
fun() -> | ||||||||||||||||||||||||||||||||
{node(), csrt:active()} | ||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||
[] | ||||||||||||||||||||||||||||||||
]), | ||||||||||||||||||||||||||||||||
%% TODO: incorporate Bad responses | ||||||||||||||||||||||||||||||||
send_json(Req, {Resp}); | ||||||||||||||||||||||||||||||||
handle_resource_status_req(Req) -> | ||||||||||||||||||||||||||||||||
ok = chttpd:verify_is_server_admin(Req), | ||||||||||||||||||||||||||||||||
send_method_not_allowed(Req, "GET,HEAD,POST"). | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
handle_replicate_req(#httpd{method = 'POST', user_ctx = Ctx, req_body = PostBody} = Req) -> | ||||||||||||||||||||||||||||||||
chttpd:validate_ctype(Req, "application/json"), | ||||||||||||||||||||||||||||||||
%% see HACK in chttpd.erl about replication | ||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Couch Stats Resource Tracker (CSRT) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should either add a readme file or not have one at all, just the title is probably not worth having. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a quick comment what it is, what it does, and why a user might want to enable it and if there are any downsides or trade-offs from it.