diff options
author | Tony Sun <tony.sun427@gmail.com> | 2021-03-10 22:03:34 -0800 |
---|---|---|
committer | Tony Sun <tony.sun427@gmail.com> | 2021-04-13 11:17:37 -0700 |
commit | 4e5df74bf6e6d66bd8efe860d178e0bd23c4e3ed (patch) | |
tree | 0e2edb2d5c10c3a1bbe00054563ac852717cd91d | |
parent | 2ae47756f9add96080e0e257e6cea31f9f074841 (diff) | |
download | couchdb-4e5df74bf6e6d66bd8efe860d178e0bd23c4e3ed.tar.gz |
add configurable http server
We add an option to spawn a new mochiweb_http server to allow for an
additional port for scraping which does not require authentication.
The default ports are 17986, 27986, 37986 across 3 nodes.
-rwxr-xr-x | dev/run | 7 | ||||
-rw-r--r-- | rel/overlay/etc/default.ini | 5 | ||||
-rw-r--r-- | setup_eunit.template | 1 | ||||
-rw-r--r-- | src/couch_prometheus/src/couch_prometheus.app.src | 2 | ||||
-rw-r--r-- | src/couch_prometheus/src/couch_prometheus.hrl | 3 | ||||
-rw-r--r-- | src/couch_prometheus/src/couch_prometheus_http.erl | 88 | ||||
-rw-r--r-- | src/couch_prometheus/src/couch_prometheus_server.erl | 12 | ||||
-rw-r--r-- | src/couch_prometheus/src/couch_prometheus_sup.erl | 8 |
8 files changed, 116 insertions, 10 deletions
@@ -287,7 +287,8 @@ def check_boot_script(ctx): @log("Prepare configuration files") def setup_configs(ctx): for idx, node in enumerate(ctx["nodes"]): - cluster_port, backend_port = get_ports(ctx, idx + ctx["node_number"]) + cluster_port, backend_port, prometheus_port = get_ports(ctx, + idx + ctx["node_number"]) env = { "prefix": toposixpath(ctx["rootdir"]), "package_author_name": "The Apache Software Foundation", @@ -300,6 +301,7 @@ def setup_configs(ctx): "node_name": "-name %s@127.0.0.1" % node, "cluster_port": cluster_port, "backend_port": backend_port, + "prometheus_port": prometheus_port, "uuid": "fake_uuid_for_dev", "_default": "", } @@ -360,7 +362,8 @@ def apply_config_overrides(ctx, content): def get_ports(ctx, idnode): assert idnode if idnode <= 5 and not ctx["auto_ports"]: - return ((10000 * idnode) + 5984, (10000 * idnode) + 5986) + return ((10000 * idnode) + 5984, (10000 * idnode) + 5986, + (10000 * idnode) + 7986) else: return tuple(get_available_ports(2)) diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini index 25f3cca37..5bdaef389 100644 --- a/rel/overlay/etc/default.ini +++ b/rel/overlay/etc/default.ini @@ -905,3 +905,8 @@ compaction = false ; The interval in seconds of how often the expiration check runs. ;cache_expiration_check_sec = 10 + +[prometheus] +additional_port = true +bind_address = 127.0.0.1 +port = {{prometheus_port}}
\ No newline at end of file diff --git a/setup_eunit.template b/setup_eunit.template index 97bee466c..3625441bd 100644 --- a/setup_eunit.template +++ b/setup_eunit.template @@ -2,6 +2,7 @@ {package_author_name, "The Apache Software Foundation"}, {cluster_port, 5984}, {backend_port, 5986}, + {prometheus_port, 17986}, {node_name, "-name couchdbtest@127.0.0.1"}, {data_dir, "/tmp"}, diff --git a/src/couch_prometheus/src/couch_prometheus.app.src b/src/couch_prometheus/src/couch_prometheus.app.src index 3080b2908..bf49e59d2 100644 --- a/src/couch_prometheus/src/couch_prometheus.app.src +++ b/src/couch_prometheus/src/couch_prometheus.app.src @@ -14,7 +14,7 @@ {description, "Aggregated metrics info for Prometheus consumption"}, {vsn, git}, {registered, []}, - {applications, [kernel, stdlib, folsom, couch_stats]}, + {applications, [kernel, stdlib, folsom, couch_stats, couch_log]}, {mod, {couch_prometheus_app, []}}, {env, []} ]}. diff --git a/src/couch_prometheus/src/couch_prometheus.hrl b/src/couch_prometheus/src/couch_prometheus.hrl index e82fb90cb..383dbfeab 100644 --- a/src/couch_prometheus/src/couch_prometheus.hrl +++ b/src/couch_prometheus/src/couch_prometheus.hrl @@ -10,4 +10,5 @@ % License for the specific language governing permissions and limitations under % the License. --define(REFRESH_INTERVAL, 60). +-define(REFRESH_INTERVAL, 5). + diff --git a/src/couch_prometheus/src/couch_prometheus_http.erl b/src/couch_prometheus/src/couch_prometheus_http.erl new file mode 100644 index 000000000..4edb53886 --- /dev/null +++ b/src/couch_prometheus/src/couch_prometheus_http.erl @@ -0,0 +1,88 @@ +-module(couch_prometheus_http). + +-compile(tuple_calls). + +-export([ + start_link/0, + handle_request/1 +]). + +-include("couch_prometheus.hrl"). +-include_lib("couch/include/couch_db.hrl"). + +start_link() -> + IP = case config:get("prometheus", "bind_address", "any") of + "any" -> any; + Else -> Else + end, + Port = config:get("prometheus", "port"), + ok = couch_httpd:validate_bind_address(IP), + + Options = [ + {name, ?MODULE}, + {loop, fun ?MODULE:handle_request/1}, + {ip, IP}, + {port, Port} + ], + case mochiweb_http:start(Options) of + {ok, Pid} -> + {ok, Pid}; + {error, Reason} -> + io:format("Failure to start Mochiweb: ~s~n", [Reason]), + {error, Reason} + end. + +handle_request(MochiReq) -> + RawUri = MochiReq:get(raw_path), + {"/" ++ Path, _, _} = mochiweb_util:urlsplit_path(RawUri), + PathParts = string:tokens(Path, "/"), try + case PathParts of + ["_node", Node, "_prometheus"] -> + send_prometheus(MochiReq, Node); + _ -> + send_error(MochiReq, 404, <<"not_found">>, <<>>) + end + catch T:R -> + Body = list_to_binary(io_lib:format("~p:~p", [T, R])), + send_error(MochiReq, 500, <<"server_error">>, Body) + end. + +send_prometheus(MochiReq, Node) -> + Headers = couch_httpd:server_header() ++ [ + {<<"Content-Type">>, <<"text/plain">>} + ], + Body = call_node(Node, couch_prometheus_server, scrape, []), + send_resp(MochiReq, 200, Headers, Body). + +send_resp(MochiReq, Status, ExtraHeaders, Body) -> + Headers = couch_httpd:server_header() ++ ExtraHeaders, + MochiReq:respond({Status, Headers, Body}). + +send_error(MochiReq, Code, Error, Reason) -> + Headers = couch_httpd:server_header() ++ [ + {<<"Content-Type">>, <<"application/json">>} + ], + JsonError = {[{<<"error">>, Error}, + {<<"reason">>, Reason}]}, + Body = ?JSON_ENCODE(JsonError), + MochiReq:respond({Code, Headers, Body}). + +call_node("_local", Mod, Fun, Args) -> + call_node(node(), Mod, Fun, Args); +call_node(Node0, Mod, Fun, Args) when is_list(Node0) -> + Node1 = try + list_to_existing_atom(Node0) + catch + error:badarg -> + NoNode = list_to_binary(Node0), + throw({not_found, <<"no such node: ", NoNode/binary>>}) + end, + call_node(Node1, Mod, Fun, Args); +call_node(Node, Mod, Fun, Args) when is_atom(Node) -> + case rpc:call(Node, Mod, Fun, Args) of + {badrpc, nodedown} -> + Reason = list_to_binary(io_lib:format("~s is down", [Node])), + throw({error, {nodedown, Reason}}); + Else -> + Else + end. diff --git a/src/couch_prometheus/src/couch_prometheus_server.erl b/src/couch_prometheus/src/couch_prometheus_server.erl index a0accba99..753e95351 100644 --- a/src/couch_prometheus/src/couch_prometheus_server.erl +++ b/src/couch_prometheus/src/couch_prometheus_server.erl @@ -21,15 +21,17 @@ ]). -export([ + scrape/0 +]). + +-export([ start_link/0, init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, - terminate/2, - - scrape/0 + terminate/2 ]). -include("couch_prometheus.hrl"). @@ -51,7 +53,6 @@ scrape() -> {ok, Metrics} = gen_server:call(?MODULE, scrape), Metrics. - handle_call(scrape, _from, #st{metrics = Metrics}=State) -> {reply, {ok, Metrics}, State}; handle_call(refresh, _from, #st{refresh=OldRT} = State) -> @@ -67,7 +68,8 @@ handle_cast(Msg, State) -> handle_info(refresh, State) -> Metrics = refresh_metrics(), - {noreply, State#st{metrics=Metrics}}; + RT = update_refresh_timer(), + {noreply, State#st{metrics=Metrics, refresh=RT}}; handle_info(Msg, State) -> {stop, {unknown_info, Msg}, State}. diff --git a/src/couch_prometheus/src/couch_prometheus_sup.erl b/src/couch_prometheus/src/couch_prometheus_sup.erl index 09ed45f12..8d8c7e078 100644 --- a/src/couch_prometheus/src/couch_prometheus_sup.erl +++ b/src/couch_prometheus/src/couch_prometheus_sup.erl @@ -28,6 +28,12 @@ init([]) -> {ok, { {one_for_one, 5, 10}, [ ?CHILD(couch_prometheus_server, worker) - ] + ] ++ maybe_start_prometheus_http() }}. +maybe_start_prometheus_http() -> + case config:get("prometheus", "additional_port", "false") of + "false" -> []; + "true" -> [?CHILD(couch_prometheus_http, worker)]; + _ -> [] + end. |