Add Beast.Insight stats collection module

This commit is contained in:
Vinnie Falco
2013-12-14 20:19:21 -08:00
parent 42692abd1c
commit d11983ae32
22 changed files with 1994 additions and 0 deletions

View File

@@ -120,6 +120,20 @@
<ClInclude Include="..\..\beast\http\impl\http-parser\http_parser.h" />
<ClInclude Include="..\..\beast\http\ParsedURL.h" />
<ClInclude Include="..\..\beast\http\URL.h" />
<ClInclude Include="..\..\beast\Insight.h" />
<ClInclude Include="..\..\beast\insight\Collector.h" />
<ClInclude Include="..\..\beast\insight\Counter.h" />
<ClInclude Include="..\..\beast\insight\CounterImpl.h" />
<ClInclude Include="..\..\beast\insight\Event.h" />
<ClInclude Include="..\..\beast\insight\EventImpl.h" />
<ClInclude Include="..\..\beast\insight\Gauge.h" />
<ClInclude Include="..\..\beast\insight\GaugeImpl.h" />
<ClInclude Include="..\..\beast\insight\Hook.h" />
<ClInclude Include="..\..\beast\insight\HookImpl.h" />
<ClInclude Include="..\..\beast\insight\Meter.h" />
<ClInclude Include="..\..\beast\insight\MeterImpl.h" />
<ClInclude Include="..\..\beast\insight\NullCollector.h" />
<ClInclude Include="..\..\beast\insight\StatsDCollector.h" />
<ClInclude Include="..\..\beast\Intrusive.h" />
<ClInclude Include="..\..\beast\intrusive\ForwardList.h" />
<ClInclude Include="..\..\beast\intrusive\IntrusiveArray.h" />
@@ -504,6 +518,37 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\Collector.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\Hook.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\Metric.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\NullCollector.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\StatsDCollector.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\insight\Insight.cpp" />
<ClCompile Include="..\..\beast\net\impl\DynamicBuffer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>

View File

@@ -318,6 +318,12 @@
<Filter Include="beast\stl">
<UniqueIdentifier>{793e2d61-14f6-4fa1-a17f-af6bbec13ba1}</UniqueIdentifier>
</Filter>
<Filter Include="beast\insight">
<UniqueIdentifier>{174b9125-76a7-4796-be97-79c2dcc751f1}</UniqueIdentifier>
</Filter>
<Filter Include="beast\insight\impl">
<UniqueIdentifier>{04f27818-7843-4ef3-967c-1761dc892342}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
@@ -1296,6 +1302,48 @@
<ClInclude Include="..\..\beast\STL.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\Insight.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\Collector.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\Counter.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\CounterImpl.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\Event.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\EventImpl.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\Gauge.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\GaugeImpl.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\Meter.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\MeterImpl.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\NullCollector.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\StatsDCollector.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\Hook.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\insight\HookImpl.h">
<Filter>beast\insight</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\containers\AbstractFifo.cpp">
@@ -1856,6 +1904,24 @@
<ClCompile Include="..\..\beast\stl\STL.cpp">
<Filter>beast\stl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\insight\Insight.cpp">
<Filter>beast\insight</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\Collector.cpp">
<Filter>beast\insight\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\Metric.cpp">
<Filter>beast\insight\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\NullCollector.cpp">
<Filter>beast\insight\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\StatsDCollector.cpp">
<Filter>beast\insight\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\insight\impl\Hook.cpp">
<Filter>beast\insight\impl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\TODO.txt">

35
beast/Insight.h Normal file
View File

@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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

96
beast/insight/Collector.h Normal file
View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <class Handler>
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

109
beast/insight/Counter.h Normal file
View File

@@ -0,0 +1,109 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <CounterImpl> 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 <class Handler>
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 <CounterImpl> m_impl;
};
}
}
#endif

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <CounterImpl>
{
public:
typedef int64 value_type;
typedef beast::function <void (Counter const&)> HandlerType;
virtual ~CounterImpl () = 0;
virtual void increment (value_type amount) = 0;
virtual void set_handler (HandlerType const& handler) = 0;
};
}
}
#endif

78
beast/insight/Event.h Normal file
View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <EventImpl> 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 <EventImpl> m_impl;
};
}
}
#endif

40
beast/insight/EventImpl.h Normal file
View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <EventImpl>
{
public:
typedef uint64 value_type;
virtual ~EventImpl () = 0;
virtual void notify (value_type value) = 0;
};
}
}
#endif

127
beast/insight/Gauge.h Normal file
View File

@@ -0,0 +1,127 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <GaugeImpl> 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 <class Handler>
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 <GaugeImpl> m_impl;
};
}
}
#endif

44
beast/insight/GaugeImpl.h Normal file
View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <GaugeImpl>
{
public:
typedef uint64 value_type;
typedef int64 difference_type;
typedef beast::function <void (Gauge const&)> 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

57
beast/insight/Hook.h Normal file
View File

@@ -0,0 +1,57 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <HookImpl> const& impl)
: m_impl (impl)
{
}
private:
shared_ptr <HookImpl> m_impl;
};
}
}
#endif

39
beast/insight/HookImpl.h Normal file
View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <HookImpl>
{
public:
typedef beast::function <void (void)> HandlerType;
virtual ~HookImpl () = 0;
};
}
}
#endif

32
beast/insight/Insight.cpp Normal file
View File

@@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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"

98
beast/insight/Meter.h Normal file
View File

@@ -0,0 +1,98 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <MeterImpl> 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 <class Handler>
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 <MeterImpl> m_impl;
};
}
}
#endif

42
beast/insight/MeterImpl.h Normal file
View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <MeterImpl>
{
public:
typedef uint64 value_type;
typedef beast::function <void (Meter const&)> HandlerType;
virtual ~MeterImpl () = 0;
virtual void increment (value_type amount) = 0;
virtual void set_handler (HandlerType const& handler) = 0;
};
}
}
#endif

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <Collector> New ();
};
}
}
#endif

View File

@@ -0,0 +1,49 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <StatsDCollector> New (IPAddress const& address,
std::string const& prefix, Journal journal);
};
}
}
#endif

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 ()
{
}
}
}

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 ()
{
}
}
}

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 ()
{
}
}
}

View File

@@ -0,0 +1,149 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <detail::NullHookImpl> ());
}
Counter make_counter (std::string const&)
{
return Counter (make_shared <detail::NullCounterImpl> ());
}
Event make_event (std::string const&)
{
return Event (make_shared <detail::NullEventImpl> ());
}
Gauge make_gauge (std::string const&)
{
return Gauge (make_shared <detail::NullGaugeImpl> ());
}
Meter make_meter (std::string const&)
{
return Meter (make_shared <detail::NullMeterImpl> ());
}
};
}
//------------------------------------------------------------------------------
shared_ptr <Collector> NullCollector::New ()
{
return beast::make_shared <detail::NullCollectorImp> ();
}
}
}

View File

@@ -0,0 +1,712 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <deque>
#include <climits>
#include <set>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/move/move.hpp>
#include <boost/optional.hpp>
namespace beast {
namespace insight {
namespace detail {
class StatsDCollectorImp;
//------------------------------------------------------------------------------
class StatsDMetricBase : public List <StatsDMetricBase>::Node
{
public:
virtual void do_process () = 0;
};
//------------------------------------------------------------------------------
class StatsDHookImpl
: public HookImpl
, public StatsDMetricBase
{
public:
StatsDHookImpl (
HandlerType const& handler,
beast::shared_ptr <StatsDCollectorImp> const& impl);
~StatsDHookImpl ();
void do_process ();
private:
StatsDHookImpl& operator= (StatsDHookImpl const&);
beast::shared_ptr <StatsDCollectorImp> m_impl;
HandlerType m_handler;
};
//------------------------------------------------------------------------------
class StatsDCounterImpl
: public CounterImpl
, public StatsDMetricBase
{
public:
StatsDCounterImpl (std::string const& name,
beast::shared_ptr <StatsDCollectorImp> 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 <CounterImpl> const& ptr);
void do_process ();
private:
StatsDCounterImpl& operator= (StatsDCounterImpl const&);
beast::shared_ptr <StatsDCollectorImp> 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 <StatsDCollectorImp> const& impl);
~StatsDEventImpl ();
void notify (EventImpl::value_type value);
void do_notify (EventImpl::value_type value,
shared_ptr <EventImpl> const& ptr);
void do_process ();
private:
StatsDEventImpl& operator= (StatsDEventImpl const&);
beast::shared_ptr <StatsDCollectorImp> m_impl;
std::string m_name;
};
//------------------------------------------------------------------------------
class StatsDGaugeImpl
: public GaugeImpl
, public StatsDMetricBase
{
public:
StatsDGaugeImpl (std::string const& name,
beast::shared_ptr <StatsDCollectorImp> 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 <GaugeImpl> const& ptr);
void do_increment (GaugeImpl::difference_type amount,
shared_ptr <GaugeImpl> const& ptr);
void do_process ();
private:
StatsDGaugeImpl& operator= (StatsDGaugeImpl const&);
beast::shared_ptr <StatsDCollectorImp> 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 <StatsDCollectorImp> 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 <MeterImpl> const& ptr);
void do_process ();
private:
StatsDMeterImpl& operator= (StatsDMeterImpl const&);
beast::shared_ptr <StatsDCollectorImp> 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 <StatsDCollectorImp>
{
private:
enum
{
//max_packet_size = 484
max_packet_size = 1472
};
struct StateType
{
List <StatsDMetricBase> metrics;
};
typedef SharedData <StateType> State;
Journal m_journal;
IPAddress m_address;
std::string m_prefix;
boost::asio::io_service m_io_service;
boost::optional <boost::asio::io_service::work> m_work;
boost::asio::deadline_timer m_timer;
boost::asio::ip::udp::socket m_socket;
std::deque <std::string> 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 <detail::StatsDHookImpl> (
handler, shared_from_this ()));
}
Counter make_counter (std::string const& name)
{
return Counter (beast::make_shared <detail::StatsDCounterImpl> (
name, shared_from_this ()));
}
Event make_event (std::string const& name)
{
return Event (beast::make_shared <detail::StatsDEventImpl> (
name, shared_from_this ()));
}
Gauge make_gauge (std::string const& name)
{
return Gauge (beast::make_shared <detail::StatsDGaugeImpl> (
name, shared_from_this ()));
}
Meter make_meter (std::string const& name)
{
return Meter (beast::make_shared <detail::StatsDMeterImpl> (
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 <boost::asio::const_buffer> buffers;
buffers.reserve (m_data.size ());
std::size_t size (0);
for (std::deque <std::string>::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 <StatsDMetricBase>::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 <StatsDCollectorImp> 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 <StatsDCollectorImp> 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 <CounterImpl> 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 <StatsDCollectorImp> 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 <EventImpl> 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 <StatsDCollectorImp> 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 <GaugeImpl> 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 <GaugeImpl> const& ptr)
{
GaugeImpl::value_type value (m_value);
if (amount > 0)
{
value +=
(amount >= std::numeric_limits <GaugeImpl::value_type>::max() - m_value)
? std::numeric_limits <GaugeImpl::value_type>::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 <StatsDCollectorImp> 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 <MeterImpl> const&)
{
m_value += amount;
m_dirty = true;
}
void StatsDMeterImpl::do_process ()
{
if (m_handler)
m_handler (Meter (shared_from_this ()));
flush ();
}
}
//------------------------------------------------------------------------------
shared_ptr <StatsDCollector> StatsDCollector::New (
IPAddress const& address, std::string const& prefix, Journal journal)
{
return beast::make_shared <detail::StatsDCollectorImp> (
address, prefix, journal);
}
}
}