%% ------------------------------------------------------------------- %% %% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved. %% %% This Source Code Form is subject to the terms of the Mozilla Public %% License, v. 2.0. If a copy of the MPL was not distributed with this %% file, You can obtain one at http://mozilla.org/MPL/2.0/. %% %% ------------------------------------------------------------------- -module(exometer_folsom). -behaviour(exometer_entry). -export([behaviour/0, new/3, delete/3, get_datapoints/3, get_value/4, update/4, reset/3, sample/3, setopts/3]). -spec behaviour() -> exometer:behaviour(). behaviour() -> entry. new(Name, counter, _Opts) -> folsom_metrics:new_counter(Name); new(Name, spiral, _Opts) -> folsom_metrics:new_spiral(Name); new(Name, histogram, Opts) -> case lists:keysearch(arg, 1, Opts) of {_, {histogram, SampleType, SampleArgs}} -> {folsom_metrics:new_histogram(Name, SampleType, SampleArgs), opt_ref(Opts)}; false -> {folsom_metrics:new_histogram(Name, slide_uniform, {60, 1028}), opt_ref(Opts)} end; new(Name, meter, Opts) -> {folsom_metrics:new_meter(Name), opt_ref(Opts)}; new(Name, meter_reader, Opts) -> {folsom_metrics:new_meter_reader(Name), opt_ref(Opts)}; new(Name, gauge, Opts) -> {folsom_metrics:new_gauge(Name), opt_ref(Opts)}; new(Name, duration, Opts) -> {folsom_metrics:new_duration(Name), opt_ref(Opts)}; new(Name, history, Opts) -> case lists:keyfind(size, 1, Opts) of {_, Sz} -> {folsom_metrics:new_history(Name, Sz), opt_ref(Opts)}; false -> {folsom_metrics:new_history(Name), opt_ref(Opts)} end. opt_ref(Opts) -> case lists:keyfind(truncate, 1, Opts) of false -> [{truncate,true}]; {_, B} when is_boolean(B) -> [{truncate,B}] end. delete(Name, _Type, _Ref) -> folsom_metrics:delete_metric(Name). update(Name, Value, counter, _Ref) -> folsom_metrics:notify_existing_metric(Name, {inc, Value}, counter); update(Name, tick, meter_reader, _Ref) -> folsom_metrics_meter_reader:tick(Name); update(Name, Value, meter_reader, _Ref) -> folsom_metrics_meter_reader:mark(Name, Value); update(Name, Value, Type, _Ref) -> folsom_metrics:notify_existing_metric(Name, Value, Type). reset(Name, counter, _Ref) -> folsom_metrics_counter:clear(Name); reset(Name, gauge, _Ref) -> folsom_metrics_gauge:clear(Name); reset(_, _, _) -> {error, unsupported}. get_value(Name, history, _Ref, DataPoints0) -> try DataPoints = datapoints(history, DataPoints0), lists:foldr( fun(events, Acc) -> [{events, just_events( folsom_metrics_history:get_events(Name))} | Acc]; (values, Acc) -> [{values, folsom_metrics_history:get_events(Name)} | Acc]; (timed_events, Acc) -> [{timed_events, timed_events( folsom_metrics_history:get_events(Name))} | Acc]; (Sz, Acc) when is_integer(Sz), Sz > 0 -> [{Sz, just_events( folsom_metrics_history:get_events(Name, Sz))} | Acc]; (info, Acc) -> [{info, folsom_metrics_history:get_value(Name)} | Acc]; (_, Acc) -> Acc end, [], DataPoints) catch error:_ -> unavailable end; get_value(Name, Type, Ref, DataPoints) -> Trunc = get_trunc_opt(Ref), Vals = get_value_(Name, Type, Ref), try [filter_dp(D, Vals, Trunc) || D <- datapoints(Type, DataPoints)] catch error:_Error -> unavailable end. get_trunc_opt(undefined) -> true; get_trunc_opt(L) -> proplists:get_value(truncate, L, true). get_datapoints(_Name, Type, _Ref) -> datapoints(Type, default). datapoints(Type, default) -> datapoints(Type); datapoints(_, L) when is_list(L) -> L. datapoints(counter) -> [value]; datapoints(gauge) -> [value]; datapoints(histogram) -> stats_datapoints(); datapoints(duration) -> [count, last |stats_datapoints()]; datapoints(spiral) -> [one, count]; datapoints(meter) -> [count,one,five,fifteen,day,mean,acceleration]; datapoints(history) -> [events, info]. filter_dp(Mean, DPs, Trunc) when Mean==mean; Mean==arithmetic_mean -> case lists:keyfind(mean, 1, DPs) of false -> case lists:keyfind(arithmetic_mean, 1, DPs) of false -> {mean, zero(Trunc)}; {_,V} -> {mean, opt_trunc(Trunc, V)} end; {_,V} -> {mean, opt_trunc(Trunc, V)} end; filter_dp(H, DPs, Trunc) when is_integer(H) -> case lists:keyfind(H, 1, DPs) of false -> case lists:keyfind(percentile, 1, DPs) of false -> {H, zero(Trunc)}; {_, Ps} -> get_dp(H, Ps, Trunc) end; {_,V} -> {H, opt_trunc(Trunc, V)} end; filter_dp(H, DPs, Trunc) -> get_dp(H, DPs, Trunc). opt_trunc(true, V) when is_float(V) -> trunc(V); opt_trunc(round, V) when is_float(V) -> round(V); opt_trunc(_, V) -> V. get_dp(K, DPs, Trunc) -> case lists:keyfind(K, 1, DPs) of false -> {K, zero(Trunc)}; {_, V} -> {K, opt_trunc(Trunc, V)} end. zero(true) -> 0; zero(round) -> 0; zero(false) -> 0.0. stats_datapoints() -> [n,mean,min,max,median,50,75,90,95,99,999]. setopts(_Entry, _Options, _Status) -> ok. sample(_Name, _Type, _Ref) -> { error, unsupported }. get_value_(Name, counter, _Ref) -> [{value, folsom_metrics_counter:get_value(Name)}]; get_value_(Name, gauge, _Ref) -> [{value, folsom_metrics_gauge:get_value(Name)}]; get_value_(Name, histogram, _Ref) -> calc_stats(folsom_metrics_histogram:get_values(Name)); get_value_(Name, duration, _Ref) -> {Name, Cnt, _Start, Last} = folsom_metrics_duration:get_value(Name), Stats = calc_stats(folsom_metrics_histogram:get_values(Name)), [{count, Cnt}, {last, Last} | Stats]; get_value_(Name, meter, _Ref) -> folsom_metrics:get_metric_value(Name); get_value_(Name, spiral, _Ref) -> folsom_metrics_spiral:get_values(Name). calc_stats(Values) -> L = length(Values), exometer_util:get_statistics(L, lists:sum(Values), lists:sort(Values)). just_events([{I, Events}|T]) when is_integer(I) -> just_events1(Events, T); just_events([]) -> []. just_events1([{event, E}|Es], T) -> [E|just_events1(Es, T)]; just_events1([], T) -> just_events(T). timed_events([{I, Events}|T]) when is_integer(I) -> timed_events(Events, I, T); timed_events([]) -> []. timed_events([{event, E}|Es], I, T) -> [{I, E}|timed_events(Es, I, T)]; timed_events([], _, T) -> timed_events(T).