Merge pull request #76 from poanetwork/ferigis.73.system_metric_collector
[#73] adding system metric collector
This commit is contained in:
commit
778ec6d73e
|
@ -13,8 +13,8 @@ config :poa_agent,
|
||||||
{:eth_information, POAAgent.Plugins.Collectors.Eth.Information, 60_000, :eth_information, [url: "http://localhost:8545", name: "Elixir-NodeJS-Integration", contact: "myemail@gmail.com"]},
|
{:eth_information, POAAgent.Plugins.Collectors.Eth.Information, 60_000, :eth_information, [url: "http://localhost:8545", name: "Elixir-NodeJS-Integration", contact: "myemail@gmail.com"]},
|
||||||
{:eth_latest_block, POAAgent.Plugins.Collectors.Eth.LatestBlock, 500, :latest_block, [url: "http://localhost:8545"]},
|
{:eth_latest_block, POAAgent.Plugins.Collectors.Eth.LatestBlock, 500, :latest_block, [url: "http://localhost:8545"]},
|
||||||
{:eth_stats, POAAgent.Plugins.Collectors.Eth.Stats, 5000, :eth_stats, [url: "http://localhost:8545"]},
|
{:eth_stats, POAAgent.Plugins.Collectors.Eth.Stats, 5000, :eth_stats, [url: "http://localhost:8545"]},
|
||||||
{:eth_pending, POAAgent.Plugins.Collectors.Eth.Pending, 500, :eth_pending, [url: "http://localhost:8545"]}
|
{:eth_pending, POAAgent.Plugins.Collectors.Eth.Pending, 500, :eth_pending, [url: "http://localhost:8545"]},
|
||||||
|
{:system_collector, POAAgent.Plugins.Collectors.System.Stats, 5_000, :system_metrics, []}
|
||||||
]
|
]
|
||||||
|
|
||||||
# configuration for transfers. The format for each collector is {collector_process_id, module, args}
|
# configuration for transfers. The format for each collector is {collector_process_id, module, args}
|
||||||
|
@ -26,8 +26,8 @@ config :poa_agent,
|
||||||
identifier: "elixirNodeJSIntegration",
|
identifier: "elixirNodeJSIntegration",
|
||||||
|
|
||||||
# Authentication parameters
|
# Authentication parameters
|
||||||
user: "BK3eiZcT",
|
user: "rUN7afCO",
|
||||||
password: "MPr1n9B-ipvpYbj",
|
password: "_3IC09xfMtAW4Hr",
|
||||||
token_url: "https://localhost:4003/session"
|
token_url: "https://localhost:4003/session"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -40,5 +40,6 @@ config :poa_agent,
|
||||||
{:eth_latest_block, [:rest_transfer]},
|
{:eth_latest_block, [:rest_transfer]},
|
||||||
{:eth_stats, [:rest_transfer]},
|
{:eth_stats, [:rest_transfer]},
|
||||||
{:eth_pending, [:rest_transfer]},
|
{:eth_pending, [:rest_transfer]},
|
||||||
{:eth_information, [:rest_transfer]}
|
{:eth_information, [:rest_transfer]},
|
||||||
|
{:system_collector, []}
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
defmodule POAAgent.Entity.System.Statistics do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
alias POAAgent.Format.POAProtocol.Data
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{
|
||||||
|
cpu_load: number,
|
||||||
|
memory_usage: number,
|
||||||
|
disk_usage: number
|
||||||
|
}
|
||||||
|
|
||||||
|
defstruct [
|
||||||
|
cpu_load: 0,
|
||||||
|
memory_usage: 0,
|
||||||
|
disk_usage: 0
|
||||||
|
]
|
||||||
|
|
||||||
|
def new(cpu_load, memory_usage, disk_usage) do
|
||||||
|
%__MODULE__{
|
||||||
|
cpu_load: cpu_load,
|
||||||
|
memory_usage: memory_usage,
|
||||||
|
disk_usage: disk_usage
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defimpl POAAgent.Entity.NameConvention do
|
||||||
|
def from_elixir_to_node(x) do
|
||||||
|
Map.from_struct(x)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defimpl Data.Format do
|
||||||
|
def to_data(x) do
|
||||||
|
Data.new("statistics", x)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -74,7 +74,7 @@ defmodule POAAgent.Plugins.Collectors.Eth.Stats do
|
||||||
{:ok, mining} <- Ethereumex.HttpClient.eth_mining(),
|
{:ok, mining} <- Ethereumex.HttpClient.eth_mining(),
|
||||||
{:ok, hashrate} <- Ethereumex.HttpClient.eth_hashrate(),
|
{:ok, hashrate} <- Ethereumex.HttpClient.eth_hashrate(),
|
||||||
{:ok, syncing} <- Ethereumex.HttpClient.eth_syncing(),
|
{:ok, syncing} <- Ethereumex.HttpClient.eth_syncing(),
|
||||||
{:ok, gas_price} <- Ethereumex.HttpClient.eth_gas_price()
|
{:ok, gas_price} <- eth_gas_price()
|
||||||
do
|
do
|
||||||
peers = String.to_integer(POAAgent.Format.Literal.Hex.decimalize(peers))
|
peers = String.to_integer(POAAgent.Format.Literal.Hex.decimalize(peers))
|
||||||
hashrate = String.to_integer(POAAgent.Format.Literal.Hex.decimalize(hashrate))
|
hashrate = String.to_integer(POAAgent.Format.Literal.Hex.decimalize(hashrate))
|
||||||
|
@ -114,6 +114,15 @@ defmodule POAAgent.Plugins.Collectors.Eth.Stats do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp eth_gas_price do
|
||||||
|
try do
|
||||||
|
Ethereumex.HttpClient.eth_gas_price()
|
||||||
|
catch
|
||||||
|
:exit, _ ->
|
||||||
|
{:ok, "0x0"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp uptime(tries, down) do
|
defp uptime(tries, down) do
|
||||||
((tries - down) / tries) * 100
|
((tries - down) / tries) * 100
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
defmodule POAAgent.Plugins.Collectors.System.Stats do
|
||||||
|
use POAAgent.Plugins.Collector
|
||||||
|
|
||||||
|
@moduledoc """
|
||||||
|
This module retrieves system metrics. Those metrics are the cpu usage, memory and disk.
|
||||||
|
In order to use it we have to add it to the config file like this:
|
||||||
|
|
||||||
|
{:system_collector, POAAgent.Plugins.Collectors.System.Stats, 60_000, :system_metrics, []}
|
||||||
|
|
||||||
|
In this example we are checking the system metrics every minute
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
alias POAAgent.Entity.System.Statistics
|
||||||
|
|
||||||
|
@typep internal_state :: %{
|
||||||
|
last_metrics: Statistics.t
|
||||||
|
}
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec init_collector(term()) :: {:ok, internal_state()}
|
||||||
|
def init_collector(_) do
|
||||||
|
stats = gather_metrics()
|
||||||
|
|
||||||
|
{:transfer, stats, %{last_metrics: stats}}
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec collect(internal_state()) :: term()
|
||||||
|
def collect(%{last_metrics: last_metrics} = state) do
|
||||||
|
case gather_metrics() do
|
||||||
|
^last_metrics ->
|
||||||
|
{:notransfer, state}
|
||||||
|
metrics ->
|
||||||
|
{:transfer, metrics, %{state | last_metrics: metrics}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec metric_type() :: String.t
|
||||||
|
def metric_type do
|
||||||
|
"system_metrics"
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec terminate(internal_state()) :: :ok
|
||||||
|
def terminate(_state) do
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defp gather_metrics() do
|
||||||
|
Statistics.new(cpu_load(), memory_usage(), disk_usage())
|
||||||
|
end
|
||||||
|
|
||||||
|
defp cpu_load do
|
||||||
|
{total, amount} =
|
||||||
|
case :cpu_sup.util([:per_cpu]) do
|
||||||
|
cpu_info when is_list(cpu_info) ->
|
||||||
|
cpu_info
|
||||||
|
|> Enum.reduce({0, 0}, fn({_, load, _, _}, {total, acc}) ->
|
||||||
|
{total + 100.0, acc + load}
|
||||||
|
end)
|
||||||
|
_ ->
|
||||||
|
{100, 0}
|
||||||
|
end
|
||||||
|
|
||||||
|
percentage(total, amount)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp memory_usage do
|
||||||
|
memory = :memsup.get_system_memory_data()
|
||||||
|
|
||||||
|
{total, amount} =
|
||||||
|
case Keyword.get(memory, :total_memory) do
|
||||||
|
nil ->
|
||||||
|
{100, 0}
|
||||||
|
total_memory ->
|
||||||
|
{total_memory, :erlang.memory(:total)}
|
||||||
|
end
|
||||||
|
|
||||||
|
percentage(total, amount)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp disk_usage do
|
||||||
|
[{_, _, usage} | _] = :disksup.get_disk_data() |> Enum.sort(&(elem(&1, 2) >= elem(&2, 2)))
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
|
||||||
|
defp percentage(total, amount) do
|
||||||
|
100 * amount / total
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -110,6 +110,7 @@ defmodule POAAgent.Plugins.Transfers.HTTP.REST do
|
||||||
{:ok, %HTTPoison.Response{status_code: 401}} ->
|
{:ok, %HTTPoison.Response{status_code: 401}} ->
|
||||||
Logger.warn("Error 401, getting a new Token")
|
Logger.warn("Error 401, getting a new Token")
|
||||||
jwt_token = new_token(state)
|
jwt_token = new_token(state)
|
||||||
|
Logger.info("The new Token is #{inspect jwt_token}")
|
||||||
result = HTTPoison.post(address, event, [@content_type_header, bearer_auth_header(jwt_token)])
|
result = HTTPoison.post(address, event, [@content_type_header, bearer_auth_header(jwt_token)])
|
||||||
{result, %State{state | token: jwt_token}}
|
{result, %State{state | token: jwt_token}}
|
||||||
{:ok, %HTTPoison.Response{status_code: error} = result} ->
|
{:ok, %HTTPoison.Response{status_code: error} = result} ->
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -19,7 +19,7 @@ defmodule POAAgent.MixProject do
|
||||||
|
|
||||||
def application do
|
def application do
|
||||||
[
|
[
|
||||||
extra_applications: [:logger],
|
extra_applications: [:logger, :os_mon],
|
||||||
mod: {POAAgent.Application, []}
|
mod: {POAAgent.Application, []}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,9 +5,10 @@ defmodule POAAgent.Entity.ProtocolTest do
|
||||||
alias POAAgent.Entity.Ethereum.Block
|
alias POAAgent.Entity.Ethereum.Block
|
||||||
alias POAAgent.Entity.Ethereum.History
|
alias POAAgent.Entity.Ethereum.History
|
||||||
alias POAAgent.Entity.Ethereum.Pending
|
alias POAAgent.Entity.Ethereum.Pending
|
||||||
alias POAAgent.Entity.Ethereum.Statistics
|
alias POAAgent.Entity.Ethereum
|
||||||
alias POAAgent.Entity.Host.Information
|
alias POAAgent.Entity.Host.Information
|
||||||
alias POAAgent.Entity.Host.Latency
|
alias POAAgent.Entity.Host.Latency
|
||||||
|
alias POAAgent.Entity.System
|
||||||
alias POAAgent.Entity
|
alias POAAgent.Entity
|
||||||
|
|
||||||
test "Data protocol test for block entity" do
|
test "Data protocol test for block entity" do
|
||||||
|
@ -39,7 +40,7 @@ defmodule POAAgent.Entity.ProtocolTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Data protocol test for statistics entity" do
|
test "Data protocol test for statistics entity" do
|
||||||
entity = %Statistics{}
|
entity = %Ethereum.Statistics{}
|
||||||
formated_entity = format_entity(entity)
|
formated_entity = format_entity(entity)
|
||||||
|
|
||||||
assert %Data{type: "statistics", body: formated_entity} == Data.Format.to_data(entity)
|
assert %Data{type: "statistics", body: formated_entity} == Data.Format.to_data(entity)
|
||||||
|
@ -52,6 +53,13 @@ defmodule POAAgent.Entity.ProtocolTest do
|
||||||
assert %Data{type: "latency", body: formated_entity} == Data.Format.to_data(entity)
|
assert %Data{type: "latency", body: formated_entity} == Data.Format.to_data(entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Data protocol test for System Stats entity" do
|
||||||
|
entity = %System.Statistics{}
|
||||||
|
formated_entity = format_entity(entity)
|
||||||
|
|
||||||
|
assert %Data{type: "statistics", body: formated_entity} == Data.Format.to_data(entity)
|
||||||
|
end
|
||||||
|
|
||||||
defp format_entity(entity) do
|
defp format_entity(entity) do
|
||||||
entity
|
entity
|
||||||
|> Entity.NameConvention.from_elixir_to_node()
|
|> Entity.NameConvention.from_elixir_to_node()
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
defmodule POAAgent.Plugins.Collectors.System.StatsTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
|
||||||
|
alias POAAgent.Plugins.Collectors.System.Stats
|
||||||
|
alias POAAgent.Entity.System.Statistics
|
||||||
|
|
||||||
|
test "sending stats to the transfer when the collector starts and after a while" do
|
||||||
|
echo_transfer = :echo_transfer
|
||||||
|
{:ok, _echo} = EchoTransfer.start(echo_transfer)
|
||||||
|
|
||||||
|
args = %{
|
||||||
|
name: :system_metrics,
|
||||||
|
transfers: [echo_transfer],
|
||||||
|
frequency: 1000,
|
||||||
|
label: :system_metrics,
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, _pid} = Stats.start_link(args)
|
||||||
|
|
||||||
|
assert_receive {:system_metrics, metric}, 20_000
|
||||||
|
assert %Statistics{cpu_load: cpu_load, memory_usage: memory_usage, disk_usage: disk_usage} = metric
|
||||||
|
assert is_number(cpu_load)
|
||||||
|
assert is_number(memory_usage)
|
||||||
|
assert is_number(disk_usage)
|
||||||
|
|
||||||
|
# we should receiver system metrics again
|
||||||
|
assert_receive {:system_metrics, metric}, 20_000
|
||||||
|
assert %Statistics{cpu_load: cpu_load, memory_usage: memory_usage, disk_usage: disk_usage} = metric
|
||||||
|
assert is_number(cpu_load)
|
||||||
|
assert is_number(memory_usage)
|
||||||
|
assert is_number(disk_usage)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue