Skip to content

Commit eb63194

Browse files
committed
Metrics
1 parent 329ea2f commit eb63194

23 files changed

+572
-9
lines changed

apps/admin_console/config/dev.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use Mix.Config
77
# watchers to your application. For example, we use it
88
# with brunch.io to recompile .js and .css sources.
99
config :admin_console, AdminConsole.Endpoint,
10-
http: [port: 4000],
10+
http: [port: String.to_integer(System.get_env("CONSOLE_PORT", "4008"))],
1111
debug_errors: true,
1212
code_reloader: true,
1313
check_origin: false,

apps/http_proxy/lib/http_proxy/application.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ defmodule HttpProxy.Application do
99
worker(HttpProxy.Blacklist, []),
1010
supervisor(Task.Supervisor, [[name: HttpProxy.SSLSupervisor]]),
1111
worker(HttpProxy.Cache, []),
12+
worker(ProxyMetrics.Endpoint, []),
1213

1314
# For pidfile :)
1415
supervisor(PidFile.Supervisor, []),
1516
]
1617

18+
HttpProxy.PlugPipelineInstrumenter.setup()
19+
HttpProxy.PlugProxyInstrumenter.setup()
20+
ProxyMetrics.MetricsPlugExporter.setup()
21+
1722
opts = [strategy: :one_for_one, name: HttpProxy.Supervisor]
1823
Supervisor.start_link(children, opts)
1924
end

apps/http_proxy/lib/http_proxy/endpoint.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ defmodule HttpProxy.Endpoint do
1111

1212
plug Plug.RequestId
1313
plug Plug.Logger, log: :info
14-
#plug Plug.Telemetry, event_prefix: [:outproxy, :plug]
14+
plug HttpProxy.PlugPipelineInstrumenter
15+
plug HttpProxy.PlugProxyInstrumenter
16+
plug Plug.Telemetry, event_prefix: [:outproxy, :plug]
1517

1618
plug HttpSetup
1719
plug Blacklist

apps/http_proxy/lib/http_proxy/http_handler.ex

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,29 @@ defmodule HttpProxy.HttpHandler do
55
def init(opts), do: opts
66

77
def call(conn, _opts) do
8-
conn
9-
|> forward_request
10-
|> cache_response
11-
|> forward_response
8+
allowed_ranges = Enum.map Application.get_env(:http_proxy, :allowed_source_ips, []), &InetCidr.parse(&1)
9+
allowed = length(Enum.filter(allowed_ranges, fn src_ips ->
10+
InetCidr.contains? src_ips, conn.remote_ip
11+
end)) > 0
12+
13+
verb = conn.method
14+
uri = "http://#{conn.host}:#{conn.port}"
15+
str_ip = {conn.remote_ip,conn.remote_ip,32} |> InetCidr.to_string
16+
17+
case allowed do
18+
true ->
19+
conn
20+
|> forward_request
21+
|> cache_response
22+
|> forward_response
23+
false ->
24+
HttpProxy.PlugProxyInstrumenter.increment_http_requests_error_denied!
25+
Logger.warn "Denied request from #{str_ip}", verb, uri
26+
conn
27+
|> send_resp(401,"")
28+
|> Map.put(:state, :sent)
29+
|> halt
30+
end
1231
end
1332

1433
defp forward_request(conn) do

apps/http_proxy/lib/http_proxy/https_handler.ex

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,24 @@ defmodule HttpProxy.HttpsHandler do
1616
allowed = length(Enum.filter(allowed_ranges, fn src_ips ->
1717
InetCidr.contains? src_ips, conn.remote_ip
1818
end)) > 0
19-
Logger.info "allowed => #{inspect allowed}", "CONNECT", "https://#{bin_host}:#{port}"
19+
20+
verb = "CONNECT"
21+
uri = "https://#{bin_host}:#{port}"
22+
23+
Logger.info "allowed => #{inspect allowed}", verb, uri
24+
str_ip = {conn.remote_ip,conn.remote_ip,32} |> InetCidr.to_string
2025

2126
case allowed do
2227
true ->
23-
Logger.info "Allowing request => #{inspect bin_host}", "CONNECT", "https://#{bin_host}:#{port}"
28+
Logger.info "Allowing request from (#{str_ip}) => #{inspect bin_host}", verb, uri
2429
conn
2530
|> https_setup
2631
|> SSLTunnel.tunnel_traffic
2732
|> Map.put(:state, :sent)
2833
|> halt
2934
false ->
35+
HttpProxy.PlugProxyInstrumenter.increment_http_requests_error_denied!
36+
Logger.warn "Denied request from #{str_ip}", verb, uri
3037
conn
3138
|> send_resp(401,"")
3239
|> Map.put(:state, :sent)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
defmodule HttpProxy.PlugPipelineInstrumenter do
2+
use Prometheus.PlugPipelineInstrumenter
3+
end
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
defmodule HttpProxy.PlugProxyInstrumenter do
2+
use Prometheus.Metric
3+
require Logger
4+
import Plug.Conn
5+
6+
def init(opts), do: opts
7+
8+
def call(conn, _opts) do
9+
case conn.method do
10+
"CONNECT" ->
11+
increment_http_requests_method_connect!
12+
_ ->
13+
increment_http_requests_method_non_connect!
14+
end
15+
conn
16+
end
17+
18+
def increment_http_requests_method_connect! do
19+
handle_counter_inc(
20+
name: :http_requests_method_connect,
21+
labels: [:method_connect, :requests]
22+
)
23+
end
24+
25+
def increment_http_requests_method_non_connect! do
26+
handle_counter_inc(
27+
name: :http_requests_method_non_connect,
28+
labels: [:method_non_connect, :requests]
29+
)
30+
end
31+
32+
def increment_http_requests_error_denied! do
33+
handle_counter_inc(
34+
name: :http_requests_error_denied,
35+
labels: [:error_denied, :requests]
36+
)
37+
end
38+
39+
def increment_http_requests_error_remote_site_down! do
40+
handle_counter_inc(
41+
name: :http_requests_error_remote_site_down,
42+
labels: [:error_remote_site_down, :requests]
43+
)
44+
end
45+
46+
def increment_http_requests_error_internal_failure! do
47+
handle_counter_inc(
48+
name: :http_requests_error_internal_failure,
49+
labels: [:error_internal_failure, :requests]
50+
)
51+
end
52+
53+
defp handle_counter_inc(args) do
54+
try do
55+
Counter.inc(args)
56+
rescue
57+
e in Prometheus.UnknownMetricError ->
58+
Logger.warn "Prometheus.UnknownMetricError: #{inspect e}"
59+
end
60+
end
61+
62+
def setup do
63+
Counter.declare(
64+
name: :http_requests_method_connect,
65+
help: "Counts the number of HTTP requests that use CONNECT verb",
66+
labels: [:method_connect, :requests]
67+
)
68+
69+
Counter.declare(
70+
name: :http_requests_method_non_connect,
71+
help: "Counts the number of HTTP requests that does NOT use CONNECT verb",
72+
labels: [:method_non_connect, :requests]
73+
)
74+
75+
Counter.declare(
76+
name: :http_requests_error_denied,
77+
help: "Counts the number of HTTP requests that errored due to the request was denied",
78+
labels: [:error_denied, :requests]
79+
)
80+
81+
Counter.declare(
82+
name: :http_requests_error_remote_site_down,
83+
help: "Counts the number of HTTP requests that errored due to the target server was down",
84+
labels: [:error_remote_site_down, :requests]
85+
)
86+
87+
Counter.declare(
88+
name: :http_requests_error_internal_failure,
89+
help: "Counts the number of HTTP requests that errored due to internal errors",
90+
labels: [:error_internal_failure, :requests]
91+
)
92+
end
93+
end

apps/http_proxy/mix.exs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ defmodule HttpProxy.Mixfile do
2626
:cowboy,
2727
:plug,
2828
:httpoison,
29-
:dns
29+
:dns,
30+
:proxy_metrics,
31+
:prometheus_ex,
3032
],
3133
mod: {HttpProxy.Application, []}
3234
]
@@ -53,6 +55,9 @@ defmodule HttpProxy.Mixfile do
5355
{:plug, "~> 1.8"},
5456
{:httpoison, "~> 1.6.2"},
5557
{:dns, "~> 2.1.2"},
58+
{:prometheus_ex, "~> 3.0"},
59+
{:prometheus_plugs, "~> 1.1.1"},
60+
{:proxy_metrics, in_umbrella: true},
5661
]
5762
end
5863
end

apps/proxy_metrics/.formatter.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

apps/proxy_metrics/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Ignore package tarball (built via "mix hex.build").
23+
metrics-*.tar
24+

0 commit comments

Comments
 (0)