Skip to content

Commit

Permalink
Make possible runtime configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
lexmag committed Nov 12, 2016
1 parent e7c768a commit 731162b
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 69 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ matrix:
elixir: 1.3.2
- otp_release: 19.0
elixir: 1.3.2
env: STATIX_TEST_RUNTIME_CONFIG=false
- otp_release: 19.0
elixir: 1.3.2
env: STATIX_TEST_RUNTIME_CONFIG=true

sudo: false

Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ The defaults are:
* host: `"127.0.0.1"`
* port: `8125`

__Note:__ by default, configuration is evaluated once, at compile time.
If you plan using other configuration at runtime, you must specify the `:runtime_config` option:

```elixir
defmodule MyApp.Statix do
use Statix, runtime_config: true
end
```

## License

This software is licensed under [the ISC license](LICENSE).
99 changes: 67 additions & 32 deletions lib/statix.ex
Original file line number Diff line number Diff line change
@@ -1,35 +1,63 @@
defmodule Statix do
defmacro __using__(_opts) do
quote location: :keep do
{host, port, prefix} = Statix.config(__MODULE__)
conn = Statix.Conn.new(host, port)
header = [conn.header | prefix]
@statix_conn %{conn | header: header, sock: __MODULE__}

def connect() do
conn = Statix.Conn.open(@statix_conn)
Process.register(conn.sock, __MODULE__)
:ok
alias __MODULE__.Conn

defmacro __using__(opts) do
current_conn =
if Keyword.get(opts, :runtime_config, false) do
quote do
@statix_header_key Module.concat(__MODULE__, :__statix_header__)

def connect() do
conn = Statix.new_conn(__MODULE__)
Application.put_env(:statix, @statix_header_key, conn.header)

Statix.open_conn(conn)
:ok
end

@compile {:inline, [current_conn: 0]}
defp current_conn() do
header = Application.fetch_env!(:statix, @statix_header_key)
%Statix.Conn{header: header, sock: __MODULE__}
end
end
else
quote do
@statix_conn Statix.new_conn(__MODULE__)

def connect() do
Statix.open_conn(@statix_conn)
:ok
end

@compile {:inline, [current_conn: 0]}
defp current_conn() do
@statix_conn
end
end
end

quote location: :keep do
unquote(current_conn)

def increment(key, val \\ 1, options \\ []) when is_number(val) do
Statix.transmit(@statix_conn, :counter, key, val, options)
Statix.transmit(current_conn(), :counter, key, val, options)
end

def decrement(key, val \\ 1, options \\ []) when is_number(val) do
Statix.transmit(@statix_conn, :counter, key, [?-, to_string(val)], options)
Statix.transmit(current_conn(), :counter, key, [?-, to_string(val)], options)
end

def gauge(key, val, options \\ [] ) do
Statix.transmit(@statix_conn, :gauge, key, val, options)
Statix.transmit(current_conn(), :gauge, key, val, options)
end

def histogram(key, val, options \\ []) do
Statix.transmit(@statix_conn, :histogram, key, val, options)
Statix.transmit(current_conn(), :histogram, key, val, options)
end

def timing(key, val, options \\ []) do
Statix.transmit(@statix_conn, :timing, key, val, options)
Statix.transmit(current_conn(), :timing, key, val, options)
end

@doc """
Expand All @@ -47,37 +75,44 @@ defmodule Statix do
end

def set(key, val, options \\ []) do
Statix.transmit(@statix_conn, :set, key, val, options)
Statix.transmit(current_conn(), :set, key, val, options)
end
end
end

def new_conn(module) do
{host, port, prefix} = load_config(module)
conn = Conn.new(host, port)
header = IO.iodata_to_binary([conn.header | prefix])
%{conn | header: header, sock: module}
end

def open_conn(%Conn{sock: module} = conn) do
conn = Conn.open(conn)
Process.register(conn.sock, module)
end

def transmit(conn, type, key, val, options \\ [])
when (is_binary(key) or is_list(key)) and is_list(options) do
if Keyword.get(options, :sample_rate, 1.0) >= :rand.uniform() do
Statix.Conn.transmit(conn, type, key, to_string(val), options)
Conn.transmit(conn, type, key, to_string(val), options)
else
:ok
end
end

def config(module) do
{prefix1, prefix2, env} = get_params(module)
{Keyword.get(env, :host, "127.0.0.1"),
Keyword.get(env, :port, 8125),
build_prefix(prefix1, prefix2)}
end

defp get_params(module) do
{env2, env1} = pull_env(module)
defp load_config(module) do
{env2, env1} =
Application.get_all_env(:statix)
|> Keyword.pop(module, [])
{prefix1, env1} = Keyword.pop_first(env1, :prefix)
{prefix2, env2} = Keyword.pop_first(env2, :prefix)
{prefix1, prefix2, Keyword.merge(env1, env2)}
end
env = Keyword.merge(env1, env2)

defp pull_env(module) do
Application.get_all_env(:statix)
|> Keyword.pop(module, [])
host = Keyword.get(env, :host, "127.0.0.1")
port = Keyword.get(env, :port, 8125)
prefix = build_prefix(prefix1, prefix2)
{host, port, prefix}
end

defp build_prefix(part1, part2) do
Expand Down
76 changes: 39 additions & 37 deletions test/statix_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,121 +24,123 @@ defmodule StatixTest do
end
end

defmodule Sample do
use Statix
runtime_config? = System.get_env("STATIX_TEST_RUNTIME_CONFIG") in ["1", "true"]
content = quote do
use Statix, runtime_config: unquote(runtime_config?)
end
Module.create(StatixSample, content, Macro.Env.location(__ENV__))

setup do
{:ok, _} = Server.start(self(), 8125)
Sample.connect
StatixSample.connect
end

test "increment/1,2,3" do
Sample.increment("sample")
StatixSample.increment("sample")
assert_receive {:server, "sample:1|c"}

Sample.increment(["sample"], 2)
StatixSample.increment(["sample"], 2)
assert_receive {:server, "sample:2|c"}

Sample.increment("sample", 2.1)
StatixSample.increment("sample", 2.1)
assert_receive {:server, "sample:2.1|c"}

Sample.increment("sample", 3, tags: ["foo:bar", "baz"])
StatixSample.increment("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:server, "sample:3|c|#foo:bar,baz"}

Sample.increment("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
StatixSample.increment("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
assert_receive {:server, "sample:3|c|@1.0|#foo,bar"}

Sample.increment("sample", 3, sample_rate: 0.0)
StatixSample.increment("sample", 3, sample_rate: 0.0)

refute_received _any
end

test "decrement/1,2,3" do
Sample.decrement("sample")
StatixSample.decrement("sample")
assert_receive {:server, "sample:-1|c"}

Sample.decrement(["sample"], 2)
StatixSample.decrement(["sample"], 2)
assert_receive {:server, "sample:-2|c"}

Sample.decrement("sample", 2.1)
StatixSample.decrement("sample", 2.1)
assert_receive {:server, "sample:-2.1|c"}

Sample.decrement("sample", 3, tags: ["foo:bar", "baz"])
StatixSample.decrement("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:server, "sample:-3|c|#foo:bar,baz"}
Sample.decrement("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
StatixSample.decrement("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])

assert_receive {:server, "sample:-3|c|@1.0|#foo,bar"}

Sample.decrement("sample", 3, sample_rate: 0.0)
StatixSample.decrement("sample", 3, sample_rate: 0.0)

refute_received _any
end

test "gauge/2,3" do
Sample.gauge(["sample"], 2)
StatixSample.gauge(["sample"], 2)
assert_receive {:server, "sample:2|g"}

Sample.gauge("sample", 2.1)
StatixSample.gauge("sample", 2.1)
assert_receive {:server, "sample:2.1|g"}

Sample.gauge("sample", 3, tags: ["foo:bar", "baz"])
StatixSample.gauge("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:server, "sample:3|g|#foo:bar,baz"}

Sample.gauge("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
StatixSample.gauge("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
assert_receive {:server, "sample:3|g|@1.0|#foo,bar"}

Sample.gauge("sample", 3, sample_rate: 0.0)
StatixSample.gauge("sample", 3, sample_rate: 0.0)

refute_received _any
end

test "histogram/2,3" do
Sample.histogram("sample", 2)
StatixSample.histogram("sample", 2)
assert_receive {:server, "sample:2|h"}

Sample.histogram("sample", 2.1)
StatixSample.histogram("sample", 2.1)
assert_receive {:server, "sample:2.1|h"}

Sample.histogram("sample", 3, tags: ["foo:bar", "baz"])
StatixSample.histogram("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:server, "sample:3|h|#foo:bar,baz"}

Sample.histogram("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
StatixSample.histogram("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
assert_receive {:server, "sample:3|h|@1.0|#foo,bar"}

Sample.histogram("sample", 3, sample_rate: 0.0)
StatixSample.histogram("sample", 3, sample_rate: 0.0)

refute_received _any
end

test "timing/2,3" do
Sample.timing(["sample"], 2)
StatixSample.timing(["sample"], 2)
assert_receive {:server, "sample:2|ms"}

Sample.timing("sample", 2.1)
StatixSample.timing("sample", 2.1)
assert_receive {:server, "sample:2.1|ms"}

Sample.timing("sample", 3, tags: ["foo:bar", "baz"])
StatixSample.timing("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:server, "sample:3|ms|#foo:bar,baz"}

Sample.timing("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
StatixSample.timing("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
assert_receive {:server, "sample:3|ms|@1.0|#foo,bar"}

Sample.timing("sample", 3, sample_rate: 0.0)
StatixSample.timing("sample", 3, sample_rate: 0.0)

refute_received _any
end

test "measure/2,3" do
expected = "the stuff"
result = Sample.measure(["sample"], fn ->
result = StatixSample.measure(["sample"], fn ->
:timer.sleep(100)
expected
end)
assert_receive {:server, <<"sample:10", _, "|ms">>}
assert result == expected

Sample.measure("sample", [sample_rate: 1.0, tags: ["foo", "bar"]], fn ->
StatixSample.measure("sample", [sample_rate: 1.0, tags: ["foo", "bar"]], fn ->
:timer.sleep(100)
end)
assert_receive {:server, <<"sample:10", _, "|ms|@1.0|#foo,bar">>}
Expand All @@ -147,19 +149,19 @@ defmodule StatixTest do
end

test "set/2,3" do
Sample.set(["sample"], 2)
StatixSample.set(["sample"], 2)
assert_receive {:server, "sample:2|s"}

Sample.set("sample", 2.1)
StatixSample.set("sample", 2.1)
assert_receive {:server, "sample:2.1|s"}

Sample.set("sample", 3, tags: ["foo:bar", "baz"])
StatixSample.set("sample", 3, tags: ["foo:bar", "baz"])
assert_receive {:server, "sample:3|s|#foo:bar,baz"}

Sample.set("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
StatixSample.set("sample", 3, sample_rate: 1.0, tags: ["foo", "bar"])
assert_receive {:server, "sample:3|s|@1.0|#foo,bar"}

Sample.set("sample", 3, sample_rate: 0.0)
StatixSample.set("sample", 3, sample_rate: 0.0)

refute_received _any
end
Expand Down

0 comments on commit 731162b

Please sign in to comment.