You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by to...@apache.org on 2021/04/14 00:23:45 UTC
[couchdb] 02/05: add configurable http server
This is an automated email from the ASF dual-hosted git repository.
tonysun83 pushed a commit to branch port-prometheus-3.x
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 4849f24c8448b4a04e4e8bd36de01ef9764f4bb8
Author: Tony Sun <to...@gmail.com>
AuthorDate: Wed Mar 10 22:03:34 2021 -0800
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.
---
dev/run | 7 +-
rel/overlay/etc/default.ini | 5 ++
setup_eunit.template | 1 +
src/couch_prometheus/src/couch_prometheus.app.src | 2 +-
src/couch_prometheus/src/couch_prometheus.hrl | 3 +-
src/couch_prometheus/src/couch_prometheus_http.erl | 88 ++++++++++++++++++++++
.../src/couch_prometheus_server.erl | 12 +--
src/couch_prometheus/src/couch_prometheus_sup.erl | 8 +-
8 files changed, 116 insertions(+), 10 deletions(-)
diff --git a/dev/run b/dev/run
index 66d990a..04c0268 100755
--- a/dev/run
+++ b/dev/run
@@ -280,7 +280,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",
@@ -293,6 +294,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": "",
}
@@ -353,7 +355,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 9dafaba..b8852b1 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -682,3 +682,8 @@ compaction = false
;source_close_timeout_sec = 600
;require_node_param = false
;require_range_param = false
+
+[prometheus]
+additional_port = true
+bind_address = 127.0.0.1
+port = {{prometheus_port}}
diff --git a/setup_eunit.template b/setup_eunit.template
index 97bee46..3625441 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 3080b29..bf49e59 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 e82fb90..383dbfe 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 0000000..4edb538
--- /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 a0accba..753e953 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 09ed45f..8d8c7e0 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.