From f88fcf55a3ff60823243092255e0c42aca179720 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 14 Dec 2013 20:19:21 -0800 Subject: [PATCH] Add Beast.Insight stats collection module --- .../Builds/VisualStudio2012/beast.vcxproj | 45 ++ .../VisualStudio2012/beast.vcxproj.filters | 66 ++ src/beast/beast/Insight.h | 35 + src/beast/beast/insight/Collector.h | 96 +++ src/beast/beast/insight/Counter.h | 109 +++ src/beast/beast/insight/CounterImpl.h | 42 ++ src/beast/beast/insight/Event.h | 78 ++ src/beast/beast/insight/EventImpl.h | 40 + src/beast/beast/insight/Gauge.h | 127 ++++ src/beast/beast/insight/GaugeImpl.h | 44 ++ src/beast/beast/insight/Hook.h | 57 ++ src/beast/beast/insight/HookImpl.h | 39 + src/beast/beast/insight/Insight.cpp | 32 + src/beast/beast/insight/Meter.h | 98 +++ src/beast/beast/insight/MeterImpl.h | 42 ++ src/beast/beast/insight/NullCollector.h | 38 + src/beast/beast/insight/StatsDCollector.h | 49 ++ src/beast/beast/insight/impl/Collector.cpp | 28 + src/beast/beast/insight/impl/Hook.cpp | 28 + src/beast/beast/insight/impl/Metric.cpp | 40 + .../beast/insight/impl/NullCollector.cpp | 149 ++++ .../beast/insight/impl/StatsDCollector.cpp | 712 ++++++++++++++++++ 22 files changed, 1994 insertions(+) create mode 100644 src/beast/beast/Insight.h create mode 100644 src/beast/beast/insight/Collector.h create mode 100644 src/beast/beast/insight/Counter.h create mode 100644 src/beast/beast/insight/CounterImpl.h create mode 100644 src/beast/beast/insight/Event.h create mode 100644 src/beast/beast/insight/EventImpl.h create mode 100644 src/beast/beast/insight/Gauge.h create mode 100644 src/beast/beast/insight/GaugeImpl.h create mode 100644 src/beast/beast/insight/Hook.h create mode 100644 src/beast/beast/insight/HookImpl.h create mode 100644 src/beast/beast/insight/Insight.cpp create mode 100644 src/beast/beast/insight/Meter.h create mode 100644 src/beast/beast/insight/MeterImpl.h create mode 100644 src/beast/beast/insight/NullCollector.h create mode 100644 src/beast/beast/insight/StatsDCollector.h create mode 100644 src/beast/beast/insight/impl/Collector.cpp create mode 100644 src/beast/beast/insight/impl/Hook.cpp create mode 100644 src/beast/beast/insight/impl/Metric.cpp create mode 100644 src/beast/beast/insight/impl/NullCollector.cpp create mode 100644 src/beast/beast/insight/impl/StatsDCollector.cpp diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj index 6a3412a1e..707588afe 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj @@ -120,6 +120,20 @@ + + + + + + + + + + + + + + @@ -504,6 +518,37 @@ true true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + true true diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 765753011..cc49cebe6 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -318,6 +318,12 @@ {793e2d61-14f6-4fa1-a17f-af6bbec13ba1} + + {174b9125-76a7-4796-be97-79c2dcc751f1} + + + {04f27818-7843-4ef3-967c-1761dc892342} + @@ -1296,6 +1302,48 @@ beast + + beast + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + + + beast\insight + @@ -1856,6 +1904,24 @@ beast\stl + + beast\insight + + + beast\insight\impl + + + beast\insight\impl + + + beast\insight\impl + + + beast\insight\impl + + + beast\insight\impl + diff --git a/src/beast/beast/Insight.h b/src/beast/beast/Insight.h new file mode 100644 index 000000000..20efda393 --- /dev/null +++ b/src/beast/beast/Insight.h @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_H_INCLUDED +#define BEAST_INSIGHT_H_INCLUDED + +#include "insight/Counter.h" +#include "insight/CounterImpl.h" +#include "insight/Event.h" +#include "insight/EventImpl.h" +#include "insight/Gauge.h" +#include "insight/GaugeImpl.h" +#include "insight/Hook.h" +#include "insight/HookImpl.h" +#include "insight/Collector.h" +#include "insight/NullCollector.h" +#include "insight/StatsDCollector.h" + +#endif diff --git a/src/beast/beast/insight/Collector.h b/src/beast/beast/insight/Collector.h new file mode 100644 index 000000000..da923d5fe --- /dev/null +++ b/src/beast/beast/insight/Collector.h @@ -0,0 +1,96 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_COLLECTOR_H_INCLUDED +#define BEAST_INSIGHT_COLLECTOR_H_INCLUDED + +#include "../stl/function.h" +#include "../stl/shared_ptr.h" + +#include "Counter.h" +#include "Event.h" +#include "Gauge.h" +#include "Hook.h" +#include "Meter.h" + +namespace beast { +namespace insight { + +/** Interface for a manager that allows collection of metrics. + + To export metrics from a class, pass and save a shared_ptr to this + interface in the class constructor. Create the metric objects + as desired (counters, events, gauges, meters, and an optional hook) + using the interface. + + @see Counter, Event, Gauge, Hook, Meter + @see NullCollector, StatsDCollector +*/ +class Collector +{ +public: + virtual ~Collector() = 0; + + /** Create a hook. + + A hook is called at each collection interval, on an implementation + defined thread. This is a convenience facility for gathering metrics + in the polling style. The typical usage is to update all the metrics + of interest in the handler. + + Handler will be called with this signature: + void handler (void) + + @see Hook + */ + /** @{ */ + template + Hook make_hook (Handler handler) + { + return make_hook (HookImpl::HandlerType (handler)); + } + + virtual Hook make_hook (HookImpl::HandlerType const& handler) = 0; + /** @} */ + + /** Create a counter with the specified name. + @see Counter + */ + virtual Counter make_counter (std::string const& name) = 0; + + /** Create an event with the specified name. + @see Event + */ + virtual Event make_event (std::string const& name) = 0; + + /** Create a gauge with the specified name. + @see Gauge + */ + virtual Gauge make_gauge (std::string const& name) = 0; + + /** Create a meter with the specified name. + @see Meter + */ + virtual Meter make_meter (std::string const& name) = 0; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/Counter.h b/src/beast/beast/insight/Counter.h new file mode 100644 index 000000000..ecffa911e --- /dev/null +++ b/src/beast/beast/insight/Counter.h @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_COUNTER_H_INCLUDED +#define BEAST_INSIGHT_COUNTER_H_INCLUDED + +#include "CounterImpl.h" + +#include "../stl/shared_ptr.h" + +namespace beast { +namespace insight { + +/** A metric for measuring an integral value. + + A counter is a gauge calculated at the server. The owner of the counter + may increment and decrement the value by an amount. + + This is a lightweight reference wrapper which is cheap to copy and assign. + When the last reference goes away, the metric is no longer collected. +*/ +class Counter +{ +public: + typedef CounterImpl::value_type value_type; + + /** Create a null metric. + A null metric reports no information. + */ + Counter () + { + } + + /** Create the metric reference the specified implementation. + Normally this won't be called directly. Instead, call the appropriate + factory function in the Collector interface. + @see Collector. + */ + explicit Counter (shared_ptr const& impl) + : m_impl (impl) + { + } + + /** Set a handler for polling. + If a handler is set, it will be called once per collection interval. + This may be used to implement polling style collection instead of + push style. + + Handler will be called with this signature: + void Handler (Counter const&); + */ + template + void set_handler (Handler handler) const + { + if (m_impl) + m_impl->set_handler (handler); + } + + /** Increment the counter. */ + /** @{ */ + void increment (value_type amount) const + { + if (m_impl) + m_impl->increment (amount); + } + + Counter const& operator+= (value_type amount) const + { increment (amount); return *this; } + + Counter const& operator-= (value_type amount) const + { increment (-amount); return *this; } + + Counter const& operator++ () const + { increment (1); return *this; } + + Counter const& operator++ (int) const + { increment (1); return *this; } + + Counter const& operator-- () const + { increment (-1); return *this; } + + Counter const& operator-- (int) const + { increment (-1); return *this; } + /** @} */ + +private: + shared_ptr m_impl; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/CounterImpl.h b/src/beast/beast/insight/CounterImpl.h new file mode 100644 index 000000000..047a98819 --- /dev/null +++ b/src/beast/beast/insight/CounterImpl.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_COUNTERIMPL_H_INCLUDED +#define BEAST_INSIGHT_COUNTERIMPL_H_INCLUDED + +namespace beast { +namespace insight { + +class Counter; + +class CounterImpl : public enable_shared_from_this +{ +public: + typedef int64 value_type; + typedef beast::function HandlerType; + + virtual ~CounterImpl () = 0; + virtual void increment (value_type amount) = 0; + virtual void set_handler (HandlerType const& handler) = 0; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/Event.h b/src/beast/beast/insight/Event.h new file mode 100644 index 000000000..a892c780b --- /dev/null +++ b/src/beast/beast/insight/Event.h @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_EVENT_H_INCLUDED +#define BEAST_INSIGHT_EVENT_H_INCLUDED + +#include "EventImpl.h" + +#include "../stl/shared_ptr.h" + +namespace beast { +namespace insight { + +/** A metric for reporting event timing. + + An event is an operation that has an associated millisecond time, or + other integral value. Because events happen at a specific moment, the + metric only supports a push-style interface. + + This is a lightweight reference wrapper which is cheap to copy and assign. + When the last reference goes away, the metric is no longer collected. +*/ +class Event +{ +public: + typedef EventImpl::value_type value_type; + + /** Create a null metric. + A null metric reports no information. + */ + Event () + { + } + + /** Create the metric reference the specified implementation. + Normally this won't be called directly. Instead, call the appropriate + factory function in the Collector interface. + @see Collector. + */ + explicit Event (shared_ptr const& impl) + : m_impl (impl) + { + } + + /** Push an event notification. + The value specifies the elapsed time in milliseconds, or any other + domain specific value. + */ + void notify (value_type value) const + { + if (m_impl) + m_impl->notify (value); + } + +private: + shared_ptr m_impl; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/EventImpl.h b/src/beast/beast/insight/EventImpl.h new file mode 100644 index 000000000..ef93a2334 --- /dev/null +++ b/src/beast/beast/insight/EventImpl.h @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_EVENTIMPL_H_INCLUDED +#define BEAST_INSIGHT_EVENTIMPL_H_INCLUDED + +namespace beast { +namespace insight { + +class Event; + +class EventImpl : public enable_shared_from_this +{ +public: + typedef uint64 value_type; + + virtual ~EventImpl () = 0; + virtual void notify (value_type value) = 0; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/Gauge.h b/src/beast/beast/insight/Gauge.h new file mode 100644 index 000000000..16fc484fd --- /dev/null +++ b/src/beast/beast/insight/Gauge.h @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_GAUGE_H_INCLUDED +#define BEAST_INSIGHT_GAUGE_H_INCLUDED + +#include "GaugeImpl.h" + +#include "../stl/shared_ptr.h" + +namespace beast { +namespace insight { + +/** A metric for measuring an integral value. + + A gauge is an instantaneous measurement of a value, like the gas gauge + in a car. The caller directly sets the value, or adjusts it by a + specified amount. The value is kept in the client rather than the collector. + + This is a lightweight reference wrapper which is cheap to copy and assign. + When the last reference goes away, the metric is no longer collected. +*/ +class Gauge +{ +public: + typedef GaugeImpl::value_type value_type; + typedef GaugeImpl::difference_type difference_type; + + /** Create a null metric. + A null metric reports no information. + */ + Gauge () + { + } + + /** Create the metric reference the specified implementation. + Normally this won't be called directly. Instead, call the appropriate + factory function in the Collector interface. + @see Collector. + */ + explicit Gauge (shared_ptr const& impl) + : m_impl (impl) + { + } + + /** Set a handler for polling. + If a handler is set, it will be called once per collection interval. + This may be used to implement polling style collection instead of + push style. + + Handler will be called with this signature: + void Handler (Gauge const&); + */ + template + void set_handler (Handler handler) const + { + if (m_impl) + m_impl->set_handler (handler); + } + + /** Set the value on the gauge. + A Collector implementation should combine multiple calls to value + changes into a single change if the calls occur within a single + collection interval. + */ + /** @{ */ + void set (value_type value) const + { + if (m_impl) + m_impl->set (value); + } + + Gauge const& operator= (value_type value) const + { set (value); return *this; } + /** @} */ + + /** Adjust the value of the gauge. */ + /** @{ */ + void increment (difference_type amount) const + { + if (m_impl) + m_impl->increment (amount); + } + + Gauge const& operator+= (difference_type amount) const + { increment (amount); return *this; } + + Gauge const& operator-= (difference_type amount) const + { increment (-amount); return *this; } + + Gauge const& operator++ () const + { increment (1); return *this; } + + Gauge const& operator++ (int) const + { increment (1); return *this; } + + Gauge const& operator-- () const + { increment (-1); return *this; } + + Gauge const& operator-- (int) const + { increment (-1); return *this; } + /** @} */ + +private: + shared_ptr m_impl; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/GaugeImpl.h b/src/beast/beast/insight/GaugeImpl.h new file mode 100644 index 000000000..0e26cb47e --- /dev/null +++ b/src/beast/beast/insight/GaugeImpl.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_GAUGEIMPL_H_INCLUDED +#define BEAST_INSIGHT_GAUGEIMPL_H_INCLUDED + +namespace beast { +namespace insight { + +class Gauge; + +class GaugeImpl : public enable_shared_from_this +{ +public: + typedef uint64 value_type; + typedef int64 difference_type; + typedef beast::function HandlerType; + + virtual ~GaugeImpl () = 0; + virtual void set (value_type value) = 0; + virtual void increment (difference_type amount) = 0; + virtual void set_handler (HandlerType const& handler) = 0; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/Hook.h b/src/beast/beast/insight/Hook.h new file mode 100644 index 000000000..06ef84490 --- /dev/null +++ b/src/beast/beast/insight/Hook.h @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_HOOK_H_INCLUDED +#define BEAST_INSIGHT_HOOK_H_INCLUDED + +#include "HookImpl.h" + +#include "../stl/shared_ptr.h" + +namespace beast { +namespace insight { + +/** A reference to a handler for performing polled collection. */ +class Hook +{ +public: + /** Create a null hook. + A null hook has no associated handler. + */ + Hook () + { } + + /** Create a hook referencing the specified implementation. + Normally this won't be called directly. Instead, call the appropriate + factory function in the Collector interface. + @see Collector. + */ + explicit Hook (shared_ptr const& impl) + : m_impl (impl) + { + } + +private: + shared_ptr m_impl; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/HookImpl.h b/src/beast/beast/insight/HookImpl.h new file mode 100644 index 000000000..cbbf37184 --- /dev/null +++ b/src/beast/beast/insight/HookImpl.h @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_HOOKIMPL_H_INCLUDED +#define BEAST_INSIGHT_HOOKIMPL_H_INCLUDED + +#include "../stl/shared_ptr.h" + +namespace beast { +namespace insight { + +class HookImpl : public enable_shared_from_this +{ +public: + typedef beast::function HandlerType; + + virtual ~HookImpl () = 0; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/Insight.cpp b/src/beast/beast/insight/Insight.cpp new file mode 100644 index 000000000..1426d5073 --- /dev/null +++ b/src/beast/beast/insight/Insight.cpp @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "../Config.h" + +#include "../../modules/beast_core/beast_core.h" // for UnitTest + +#include "../Insight.h" + +#include "impl/Collector.cpp" +#include "impl/Hook.cpp" +#include "impl/Metric.cpp" +#include "impl/NullCollector.cpp" +#include "impl/StatsDCollector.cpp" diff --git a/src/beast/beast/insight/Meter.h b/src/beast/beast/insight/Meter.h new file mode 100644 index 000000000..bf2090c1d --- /dev/null +++ b/src/beast/beast/insight/Meter.h @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_METER_H_INCLUDED +#define BEAST_INSIGHT_METER_H_INCLUDED + +#include "MeterImpl.h" + +#include "../stl/shared_ptr.h" + +namespace beast { +namespace insight { + +/** A metric for measuring an integral value. + + A meter may be thought of as an increment-only counter. + + This is a lightweight reference wrapper which is cheap to copy and assign. + When the last reference goes away, the metric is no longer collected. +*/ +class Meter +{ +public: + typedef MeterImpl::value_type value_type; + + /** Create a null metric. + A null metric reports no information. + */ + Meter () + { + } + + /** Create the metric reference the specified implementation. + Normally this won't be called directly. Instead, call the appropriate + factory function in the Collector interface. + @see Collector. + */ + explicit Meter (shared_ptr const& impl) + : m_impl (impl) + { + } + + /** Set a handler for polling. + If a handler is set, it will be called once per collection interval. + This may be used to implement polling style collection instead of + push style. + + Handler will be called with this signature: + void Handler (Meter const&); + */ + template + void set_handler (Handler handler) const + { + m_impl->set_handler (handler); + } + + /** Increment the meter. */ + /** @{ */ + void increment (value_type amount) const + { + if (m_impl) + m_impl->increment (amount); + } + + Meter const& operator+= (value_type amount) const + { increment (amount); return *this; } + + Meter const& operator++ () const + { increment (1); return *this; } + + Meter const& operator++ (int) const + { increment (1); return *this; } + /** @} */ + +private: + shared_ptr m_impl; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/MeterImpl.h b/src/beast/beast/insight/MeterImpl.h new file mode 100644 index 000000000..057bd155d --- /dev/null +++ b/src/beast/beast/insight/MeterImpl.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_METERIMPL_H_INCLUDED +#define BEAST_INSIGHT_METERIMPL_H_INCLUDED + +namespace beast { +namespace insight { + +class Meter; + +class MeterImpl : public enable_shared_from_this +{ +public: + typedef uint64 value_type; + typedef beast::function HandlerType; + + virtual ~MeterImpl () = 0; + virtual void increment (value_type amount) = 0; + virtual void set_handler (HandlerType const& handler) = 0; +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/NullCollector.h b/src/beast/beast/insight/NullCollector.h new file mode 100644 index 000000000..af1f22d6b --- /dev/null +++ b/src/beast/beast/insight/NullCollector.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED +#define BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED + +#include "Collector.h" + +namespace beast { +namespace insight { + +/** A Collector which does not collect metrics. */ +class NullCollector : public Collector +{ +public: + static shared_ptr New (); +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/StatsDCollector.h b/src/beast/beast/insight/StatsDCollector.h new file mode 100644 index 000000000..931c478f9 --- /dev/null +++ b/src/beast/beast/insight/StatsDCollector.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED +#define BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED + +#include "Collector.h" + +#include "../net/IPAddress.h" + +namespace beast { +namespace insight { + +/** A Collector that reports metrics to a StatsD server. + Reference: + https://github.com/b/statsd_spec +*/ +class StatsDCollector : public Collector +{ +public: + /** Create a StatsD collector. + @param address The IP address and port of the StatsD server. + @param prefix A string pre-pended before each metric name. + @param journal Destination for logging output. + */ + static shared_ptr New (IPAddress const& address, + std::string const& prefix, Journal journal); +}; + +} +} + +#endif diff --git a/src/beast/beast/insight/impl/Collector.cpp b/src/beast/beast/insight/impl/Collector.cpp new file mode 100644 index 000000000..2ab1d2fc5 --- /dev/null +++ b/src/beast/beast/insight/impl/Collector.cpp @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace beast { +namespace insight { + +Collector::~Collector () +{ +} + +} +} diff --git a/src/beast/beast/insight/impl/Hook.cpp b/src/beast/beast/insight/impl/Hook.cpp new file mode 100644 index 000000000..e9392a59f --- /dev/null +++ b/src/beast/beast/insight/impl/Hook.cpp @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace beast { +namespace insight { + +HookImpl::~HookImpl () +{ +} + +} +} diff --git a/src/beast/beast/insight/impl/Metric.cpp b/src/beast/beast/insight/impl/Metric.cpp new file mode 100644 index 000000000..f40cd493b --- /dev/null +++ b/src/beast/beast/insight/impl/Metric.cpp @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace beast { +namespace insight { + +CounterImpl::~CounterImpl () +{ +} + +EventImpl::~EventImpl () +{ +} + +GaugeImpl::~GaugeImpl () +{ +} + +MeterImpl::~MeterImpl () +{ +} + +} +} diff --git a/src/beast/beast/insight/impl/NullCollector.cpp b/src/beast/beast/insight/impl/NullCollector.cpp new file mode 100644 index 000000000..f1ab857f6 --- /dev/null +++ b/src/beast/beast/insight/impl/NullCollector.cpp @@ -0,0 +1,149 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace beast { +namespace insight { + +namespace detail { + +class NullHookImpl : public HookImpl +{ +private: + NullHookImpl& operator= (NullHookImpl const&); +}; + +//------------------------------------------------------------------------------ + +class NullCounterImpl : public CounterImpl +{ +public: + void increment (value_type) + { + } + + void set_handler (HandlerType const&) + { + } + +private: + NullCounterImpl& operator= (NullCounterImpl const&); +}; + +//------------------------------------------------------------------------------ + +class NullEventImpl : public EventImpl +{ +public: + void notify (value_type) + { + } + +private: + NullEventImpl& operator= (NullEventImpl const&); +}; + +//------------------------------------------------------------------------------ + +class NullGaugeImpl : public GaugeImpl +{ +public: + void set (value_type) + { + } + + void increment (difference_type) + { + } + + void set_handler (HandlerType const&) + { + } + +private: + NullGaugeImpl& operator= (NullGaugeImpl const&); +}; + +//------------------------------------------------------------------------------ + +class NullMeterImpl : public MeterImpl +{ +public: + void increment (value_type) + { + } + + void set_handler (HandlerType const&) + { + } + +private: + NullMeterImpl& operator= (NullMeterImpl const&); +}; + +//------------------------------------------------------------------------------ + +class NullCollectorImp : public NullCollector +{ +private: +public: + NullCollectorImp () + { + } + + ~NullCollectorImp () + { + } + + Hook make_hook (HookImpl::HandlerType const&) + { + return Hook (make_shared ()); + } + + Counter make_counter (std::string const&) + { + return Counter (make_shared ()); + } + + Event make_event (std::string const&) + { + return Event (make_shared ()); + } + + Gauge make_gauge (std::string const&) + { + return Gauge (make_shared ()); + } + + Meter make_meter (std::string const&) + { + return Meter (make_shared ()); + } +}; + +} + +//------------------------------------------------------------------------------ + +shared_ptr NullCollector::New () +{ + return beast::make_shared (); +} + +} +} diff --git a/src/beast/beast/insight/impl/StatsDCollector.cpp b/src/beast/beast/insight/impl/StatsDCollector.cpp new file mode 100644 index 000000000..86d540d3c --- /dev/null +++ b/src/beast/beast/insight/impl/StatsDCollector.cpp @@ -0,0 +1,712 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../../asio/IPAddressConversion.h" +#include "../../threads/SharedData.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace beast { +namespace insight { + +namespace detail { + +class StatsDCollectorImp; + +//------------------------------------------------------------------------------ + +class StatsDMetricBase : public List ::Node +{ +public: + virtual void do_process () = 0; +}; + +//------------------------------------------------------------------------------ + +class StatsDHookImpl + : public HookImpl + , public StatsDMetricBase +{ +public: + StatsDHookImpl ( + HandlerType const& handler, + beast::shared_ptr const& impl); + + ~StatsDHookImpl (); + + void do_process (); + +private: + StatsDHookImpl& operator= (StatsDHookImpl const&); + + beast::shared_ptr m_impl; + HandlerType m_handler; +}; + +//------------------------------------------------------------------------------ + +class StatsDCounterImpl + : public CounterImpl + , public StatsDMetricBase +{ +public: + StatsDCounterImpl (std::string const& name, + beast::shared_ptr const& impl); + + ~StatsDCounterImpl (); + + void increment (CounterImpl::value_type amount); + void set_handler (HandlerType const& handler); + + void flush (); + void do_increment (CounterImpl::value_type amount, + shared_ptr const& ptr); + void do_process (); + +private: + StatsDCounterImpl& operator= (StatsDCounterImpl const&); + + beast::shared_ptr m_impl; + std::string m_name; + CounterImpl::value_type m_value; + bool m_dirty; + HandlerType m_handler; +}; + +//------------------------------------------------------------------------------ + +class StatsDEventImpl + : public EventImpl +{ +public: + StatsDEventImpl (std::string const& name, + beast::shared_ptr const& impl); + + ~StatsDEventImpl (); + + void notify (EventImpl::value_type value); + + void do_notify (EventImpl::value_type value, + shared_ptr const& ptr); + void do_process (); + +private: + StatsDEventImpl& operator= (StatsDEventImpl const&); + + beast::shared_ptr m_impl; + std::string m_name; +}; + +//------------------------------------------------------------------------------ + +class StatsDGaugeImpl + : public GaugeImpl + , public StatsDMetricBase +{ +public: + StatsDGaugeImpl (std::string const& name, + beast::shared_ptr const& impl); + + ~StatsDGaugeImpl (); + + void set (GaugeImpl::value_type value); + void increment (GaugeImpl::difference_type amount); + void set_handler (HandlerType const& handler); + + void flush (); + void do_set (GaugeImpl::value_type value, + shared_ptr const& ptr); + void do_increment (GaugeImpl::difference_type amount, + shared_ptr const& ptr); + void do_process (); + +private: + StatsDGaugeImpl& operator= (StatsDGaugeImpl const&); + + beast::shared_ptr m_impl; + std::string m_name; + GaugeImpl::value_type m_last_value; + GaugeImpl::value_type m_value; + bool m_dirty; + HandlerType m_handler; +}; + +//------------------------------------------------------------------------------ + +class StatsDMeterImpl + : public MeterImpl + , public StatsDMetricBase +{ +public: + explicit StatsDMeterImpl (std::string const& name, + beast::shared_ptr const& impl); + + ~StatsDMeterImpl (); + + void increment (MeterImpl::value_type amount); + void set_handler (HandlerType const& handler); + + void flush (); + void do_increment (MeterImpl::value_type amount, + shared_ptr const& ptr); + void do_process (); + +private: + StatsDMeterImpl& operator= (StatsDMeterImpl const&); + + beast::shared_ptr m_impl; + std::string m_name; + MeterImpl::value_type m_value; + bool m_dirty; + HandlerType m_handler; +}; + +//------------------------------------------------------------------------------ + +class StatsDCollectorImp + : public StatsDCollector + , public beast::enable_shared_from_this +{ +private: + enum + { + //max_packet_size = 484 + max_packet_size = 1472 + }; + + struct StateType + { + List metrics; + }; + + typedef SharedData State; + + Journal m_journal; + IPAddress m_address; + std::string m_prefix; + boost::asio::io_service m_io_service; + boost::optional m_work; + boost::asio::deadline_timer m_timer; + boost::asio::ip::udp::socket m_socket; + std::deque m_data; + State m_state; + + // Must come last for order of init + beast::thread m_thread; + + static boost::asio::ip::udp::endpoint to_endpoint ( + IPAddress const &address) + { + if (address.isV4 ()) + { + return boost::asio::ip::udp::endpoint ( + boost::asio::ip::address_v4 ( + address.v4().value), address.port ()); + } + + // VFALCO TODO IPv6 support + bassertfalse; + return boost::asio::ip::udp::endpoint ( + boost::asio::ip::address_v6 (), 0); + } + +public: + StatsDCollectorImp ( + IPAddress const& address, + std::string const& prefix, + Journal journal) + : m_journal (journal) + , m_address (address) + , m_prefix (prefix) + , m_work (boost::ref (m_io_service)) + , m_timer (m_io_service) + , m_socket (m_io_service) + , m_thread (&StatsDCollectorImp::run, this) + { + } + + ~StatsDCollectorImp () + { + boost::system::error_code ec; + m_timer.cancel (ec); + + m_work = boost::none; + m_thread.join (); + } + + Hook make_hook (HookImpl::HandlerType const& handler) + { + return Hook (beast::make_shared ( + handler, shared_from_this ())); + } + + Counter make_counter (std::string const& name) + { + return Counter (beast::make_shared ( + name, shared_from_this ())); + } + + Event make_event (std::string const& name) + { + return Event (beast::make_shared ( + name, shared_from_this ())); + } + + Gauge make_gauge (std::string const& name) + { + return Gauge (beast::make_shared ( + name, shared_from_this ())); + } + + Meter make_meter (std::string const& name) + { + return Meter (beast::make_shared ( + name, shared_from_this ())); + } + + //-------------------------------------------------------------------------- + + void add (StatsDMetricBase& metric) + { + State::Access state (m_state); + state->metrics.push_back (metric); + } + + void remove (StatsDMetricBase& metric) + { + State::Access state (m_state); + state->metrics.erase (state->metrics.iterator_to (metric)); + } + + //-------------------------------------------------------------------------- + + boost::asio::io_service& get_io_service () + { + return m_io_service; + } + + std::string const& prefix () const + { + return m_prefix; + } + + void do_post_buffer (std::string const& buffer) + { + m_journal.info << + buffer; + m_data.emplace_back (buffer); + } + + void post_buffer (std::string&& buffer) + { + m_io_service.dispatch (boost::bind ( + &StatsDCollectorImp::do_post_buffer, this, + boost::move (buffer))); + } + + void on_send (boost::system::error_code ec, std::size_t) + { + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec) + { + m_journal.error << + "async_send failed: " << ec.message(); + return; + } + } + + // Send what we have + void send_buffers () + { + // Break up the array of strings into blocks + // that each fit into one UDP packet. + // + boost::system::error_code ec; + std::vector buffers; + buffers.reserve (m_data.size ()); + std::size_t size (0); + for (std::deque ::const_iterator iter (m_data.begin()); + iter != m_data.end(); ++iter) + { + std::string const& buffer (*iter); + std::size_t const length (buffer.size ()); + check_precondition (! buffer.empty ()); + if (! buffers.empty () && (size + length) > max_packet_size) + { + m_socket.async_send (buffers, boost::bind ( + &StatsDCollectorImp::on_send, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + buffers.clear (); + size = 0; + } + buffers.emplace_back (&buffer[0], length); + size += length; + } + if (! buffers.empty ()) + { + m_socket.async_send (buffers, boost::bind ( + &StatsDCollectorImp::on_send, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + m_data.clear (); + } + + void set_timer () + { + m_timer.expires_from_now (boost::posix_time::seconds (1)); + m_timer.async_wait (boost::bind ( + &StatsDCollectorImp::on_timer, this, + boost::asio::placeholders::error)); + } + + void on_timer (boost::system::error_code ec) + { + if (ec == boost::asio::error::operation_aborted) + return; + + if (ec) + { + m_journal.error << + "on_timer failed: " << ec.message(); + return; + } + + State::Access state (m_state); + + for (List ::iterator iter (state->metrics.begin()); + iter != state->metrics.end(); ++iter) + iter->do_process(); + + send_buffers (); + + m_journal.info << + "on_timer"; + + set_timer (); + } + + void run () + { + m_journal.sink().console (true); + + boost::system::error_code ec; + + if (m_socket.connect (to_endpoint (m_address), ec)) + { + m_journal.error << + "Connect failed: " << ec.message(); + return; + } + + set_timer (); + + m_io_service.run (); + + m_socket.shutdown ( + boost::asio::ip::udp::socket::shutdown_send, ec); + + m_socket.close (); + + m_io_service.poll (); + } +}; + +//------------------------------------------------------------------------------ + +StatsDHookImpl::StatsDHookImpl (HandlerType const& handler, + beast::shared_ptr const& impl) + : m_impl (impl) + , m_handler (handler) +{ + m_impl->add (*this); +} + +StatsDHookImpl::~StatsDHookImpl () +{ + m_impl->remove (*this); +} + +void StatsDHookImpl::do_process () +{ + m_handler (); +} + +//------------------------------------------------------------------------------ + +StatsDCounterImpl::StatsDCounterImpl (std::string const& name, + beast::shared_ptr const& impl) + : m_impl (impl) + , m_name (name) + , m_value (0) + , m_dirty (false) +{ + m_impl->add (*this); +} + +StatsDCounterImpl::~StatsDCounterImpl () +{ + m_impl->remove (*this); +} + +void StatsDCounterImpl::increment (CounterImpl::value_type amount) +{ + m_impl->get_io_service().dispatch (boost::bind ( + &StatsDCounterImpl::do_increment, this, amount, shared_from_this())); +} + +void StatsDCounterImpl::set_handler (HandlerType const& handler) +{ + m_handler = handler; +} + +void StatsDCounterImpl::flush () +{ + if (m_dirty) + { + m_dirty = false; + std::stringstream ss; + ss << + m_impl->prefix() << "." << + m_name << ":" << + m_value << "|c" << + "\n"; + m_value = 0; + m_impl->post_buffer (ss.str ()); + } +} + +void StatsDCounterImpl::do_increment (CounterImpl::value_type amount, + shared_ptr const&) +{ + m_value += amount; + m_dirty = true; +} + +void StatsDCounterImpl::do_process () +{ + if (m_handler) + m_handler (Counter (shared_from_this ())); + flush (); +} + +//------------------------------------------------------------------------------ + +StatsDEventImpl::StatsDEventImpl (std::string const& name, + beast::shared_ptr const& impl) + : m_impl (impl) + , m_name (name) +{ +} + +StatsDEventImpl::~StatsDEventImpl () +{ +} + +void StatsDEventImpl::notify (EventImpl::value_type value) +{ + m_impl->get_io_service().dispatch (boost::bind ( + &StatsDEventImpl::do_notify, this, value, shared_from_this())); +} + +void StatsDEventImpl::do_notify (EventImpl::value_type value, + shared_ptr const&) +{ + std::stringstream ss; + ss << + m_impl->prefix() << "." << + m_name << ":" << + value << "|ms" << + "\n"; + m_impl->post_buffer (ss.str ()); +} + +//------------------------------------------------------------------------------ + +StatsDGaugeImpl::StatsDGaugeImpl (std::string const& name, + beast::shared_ptr const& impl) + : m_impl (impl) + , m_name (name) + , m_last_value (0) + , m_value (0) + , m_dirty (false) +{ + m_impl->add (*this); +} + +StatsDGaugeImpl::~StatsDGaugeImpl () +{ + m_impl->remove (*this); +} + +void StatsDGaugeImpl::set (GaugeImpl::value_type value) +{ + m_impl->get_io_service().dispatch (boost::bind ( + &StatsDGaugeImpl::do_set, this, value, shared_from_this ())); +} + +void StatsDGaugeImpl::increment (GaugeImpl::difference_type amount) +{ + m_impl->get_io_service().dispatch (boost::bind ( + &StatsDGaugeImpl::do_increment, this, amount, shared_from_this())); +} + +void StatsDGaugeImpl::set_handler (HandlerType const& handler) +{ + m_handler = handler; +} + +void StatsDGaugeImpl::flush () +{ + if (m_dirty) + { + m_dirty = false; + std::stringstream ss; + ss << + m_impl->prefix() << "." << + m_name << ":" << + m_value << "|c" << + "\n"; + m_impl->post_buffer (ss.str ()); + } +} + +void StatsDGaugeImpl::do_set (GaugeImpl::value_type value, + shared_ptr const&) +{ + m_value = value; + + if (m_value != m_last_value) + { + m_last_value = m_value; + m_dirty = true; + } +} + +void StatsDGaugeImpl::do_increment (GaugeImpl::difference_type amount, + shared_ptr const& ptr) +{ + GaugeImpl::value_type value (m_value); + + if (amount > 0) + { + value += + (amount >= std::numeric_limits ::max() - m_value) + ? std::numeric_limits ::max() - m_value + : GaugeImpl::value_type (amount); + } + else if (amount < 0) + { + value -= + (std::abs (amount) >= m_value) + ? m_value + : std::abs (amount); + } + + do_set (value, ptr); +} + +void StatsDGaugeImpl::do_process () +{ + if (m_handler) + m_handler (Gauge (shared_from_this ())); + flush (); +} + +//------------------------------------------------------------------------------ + +StatsDMeterImpl::StatsDMeterImpl (std::string const& name, + beast::shared_ptr const& impl) + : m_impl (impl) + , m_name (name) + , m_value (0) + , m_dirty (false) +{ + m_impl->add (*this); +} + +StatsDMeterImpl::~StatsDMeterImpl () +{ + m_impl->remove (*this); +} + +void StatsDMeterImpl::increment (MeterImpl::value_type amount) +{ + m_impl->get_io_service().dispatch (boost::bind ( + &StatsDMeterImpl::do_increment, this, amount, shared_from_this())); +} + +void StatsDMeterImpl::set_handler (HandlerType const& handler) +{ + m_handler = handler; +} + +void StatsDMeterImpl::flush () +{ + if (m_dirty) + { + m_dirty = false; + std::stringstream ss; + ss << + m_impl->prefix() << "." << + m_name << ":" << + m_value << "|m" << + "\n"; + m_value = 0; + m_impl->post_buffer (ss.str ()); + } +} + +void StatsDMeterImpl::do_increment (MeterImpl::value_type amount, + shared_ptr const&) +{ + m_value += amount; + m_dirty = true; +} + +void StatsDMeterImpl::do_process () +{ + if (m_handler) + m_handler (Meter (shared_from_this ())); + flush (); +} + +} + +//------------------------------------------------------------------------------ + +shared_ptr StatsDCollector::New ( + IPAddress const& address, std::string const& prefix, Journal journal) +{ + return beast::make_shared ( + address, prefix, journal); +} + +} +}