#pragma once
#include <util/datetime/base.h>
#include <util/generic/algorithm.h>
#include <util/generic/list.h>
#include <util/generic/map.h>
#include <util/generic/ptr.h>
#include <util/generic/singleton.h>
#include <util/generic/vector.h>
#include <util/str_stl.h>
#include <util/stream/output.h>
#include <util/string/util.h>
#include <library/cpp/deprecated/atomic/atomic.h>
#include <util/system/defaults.h>
#include <util/system/guard.h>
#include <util/system/sem.h>
#include <util/system/spinlock.h>
#include <array>
namespace NMonitoring {
#define BEGIN_OUTPUT_COUNTERS \
void OutputImpl(IOutputStream& out) { \
char prettyBuf[32];
#define END_OUTPUT_COUNTERS \
out.Flush(); \
}
#define OUTPUT_NAMED_COUNTER(var, name) out << name << ": \t" << var << NMonitoring::PrettyNum(var, prettyBuf, 32) << '\n'
#define OUTPUT_COUNTER(var) OUTPUT_NAMED_COUNTER(var, #var);
char* PrettyNumShort(i64 val, char* buf, size_t size);
char* PrettyNum(i64 val, char* buf, size_t size);
// This class is deprecated. Please consider to use
// library/cpp/monlib/metrics instead. See more info at
// https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/
class TDeprecatedCounter {
public:
using TValue = TAtomic;
using TValueBase = TAtomicBase;
TDeprecatedCounter()
: Value()
, Derivative(false)
{
}
TDeprecatedCounter(TValueBase value, bool derivative = false)
: Value(value)
, Derivative(derivative)
{
}
bool ForDerivative() const {
return Derivative;
}
operator TValueBase() const {
return AtomicGet(Value);
}
TValueBase Val() const {
return AtomicGet(Value);
}
void Set(TValueBase val) {
AtomicSet(Value, val);
}
TValueBase Inc() {
return AtomicIncrement(Value);
}
TValueBase Dec() {
return AtomicDecrement(Value);
}
TValueBase Add(const TValueBase val) {
return AtomicAdd(Value, val);
}
TValueBase Sub(const TValueBase val) {
return AtomicAdd(Value, -val);
}
// operator overloads convinient
void operator++() {
Inc();
}
void operator++(int) {
Inc();
}
void operator--() {
Dec();
}
void operator--(int) {
Dec();
}
void operator+=(TValueBase rhs) {
Add(rhs);
}
void operator-=(TValueBase rhs) {
Sub(rhs);
}
TValueBase operator=(TValueBase rhs) {
AtomicSwap(&Value, rhs);
return rhs;
}
bool operator!() const {
return AtomicGet(Value) == 0;
}
TAtomic& GetAtomic() {
return Value;
}
private:
TAtomic Value;
bool Derivative;
};
template <typename T>
struct TDeprecatedCountersBase {
virtual ~TDeprecatedCountersBase() {
}
virtual void OutputImpl(IOutputStream&) = 0;
static T& Instance() {
return *Singleton<T>();
}
static void Output(IOutputStream& out) {
Instance().OutputImpl(out);
}
};
// This class is deprecated. Please consider to use
// library/cpp/monlib/metrics instead. See more info at
// https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/
//
// Groups of G counters, defined by T type.
// Less(a,b) returns true, if a < b.
// It's threadsafe.
template <typename T, typename G, typename TL = TLess<T>>
class TDeprecatedCounterGroups {
public:
typedef TMap<T, G*> TGroups;
typedef TVector<T> TGroupsNames;
typedef THolder<TGroupsNames> TGroupsNamesPtr;
private:
class TCollection {
struct TElement {
T* Name;
G* Counters;
public:
static bool Compare(const TElement& a, const TElement& b) {
return Less(*(a.Name), *(b.Name));
}
}; // TElement
private:
TArrayHolder<TElement> Elements;
size_t Size;
public:
TCollection()
: Size(0)
{
}
TCollection(const TCollection& collection)
: Elements(new TElement[collection.Size])
, Size(collection.Size)
{
for (int i = 0; i < Size; ++i) {
Elements[i] = collection.Elements[i];
}
}
TCollection(const TCollection& collection, T* name, G* counters)
: Elements(new TElement[collection.Size + 1])
, Size(collection.Size + 1)
{
for (size_t i = 0; i < Size - 1; ++i) {
Elements[i] = collection.Elements[i];
}
Elements[Size - 1].Name = name;
Elements[Size - 1].Counters = counters;
for (size_t i = 1; i < Size; ++i) {
size_t j = i;
while (j > 0 &&
TElement::Compare(Elements[j], Elements[j - 1])) {
std::swap(Elements[j], Elements[j - 1]);
--j;
}
}
}
G* Find(const T& name) const {
G* result = nullptr;
if (Size == 0) {
return nullptr;
}
size_t l = 0;
size_t r = Size - 1;
while (l < r) {
size_t m = (l + r) / 2;
if (Less(*(Elements[m].Name), name)) {
l = m + 1;
} else {
r = m;
}
}
if (!Less(*(Elements[l].Name), name) && !Less(name, *(Elements[l].Name))) {
result = Elements[l].Counters;
}
return result;
}
void Free() {
for (size_t i = 0; i < Size; ++i) {
T* name = Elements[i].Name;
G* counters = Elements[i].Counters;
Elements[i].Name = nullptr;
Elements[i].Counters = nullptr;
delete name;
delete counters;
}
Size = 0;
}
TGroupsNamesPtr GetNames() const {
TGroupsNamesPtr result(new TGroupsNames());
for (size_t i = 0; i < Size; ++i) {
result->push_back(*(Elements[i].Name));
}
return result;
}
}; // TCollection
struct TOldGroup {
TCollection* Collection;
ui64 Time;
};
private:
TCollection* Groups;
TList<TOldGroup> OldGroups;
TSpinLock AddMutex;
ui64 Timeout;
static TL Less;
private:
G* Add(const T& name) {
TGuard<TSpinLock> guard(AddMutex);
G* result = Groups->Find(name);
if (result == nullptr) {
T* newName = new T(name);
G* newCounters = new G();
TCollection* newGroups =
new TCollection(*Groups, newName, newCounters);
ui64 now = ::Now().MicroSeconds();
TOldGroup group;
group.Collection = Groups;
group.Time = now;
OldGroups.push_back(group);
for (ui32 i = 0; i < 5; ++i) {
if (OldGroups.front().Time + Timeout < now) {
delete OldGroups.front().Collection;
OldGroups.front().Collection = nullptr;
OldGroups.pop_front();
} else {
break;
}
}
Groups = newGroups;
result = Groups->Find(name);
}
return result;
}
public:
TDeprecatedCounterGroups(ui64 timeout = 5 * 1000000L) {
Groups = new TCollection();
Timeout = timeout;
}
virtual ~TDeprecatedCounterGroups() {
TGuard<TSpinLock> guard(AddMutex);
Groups->Free();
delete Groups;
Groups = nullptr;
typename TList<TOldGroup>::iterator i;
for (i = OldGroups.begin(); i != OldGroups.end(); ++i) {
delete i->Collection;
i->Collection = nullptr;
}
OldGroups.clear();
}
bool Has(const T& name) const {
TCollection* groups = Groups;
return groups->Find(name) != nullptr;
}
G* Find(const T& name) const {
TCollection* groups = Groups;
return groups->Find(name);
}
// Get group with the name, if it exists.
// If there is no group with the name, add new group.
G& Get(const T& name) {
G* result = Find(name);
if (result == nullptr) {
result = Add(name);
Y_ASSERT(result != nullptr);
}
return *result;
}
// Get copy of groups names array.
TGroupsNamesPtr GetGroupsNames() const {
TCollection* groups = Groups;
TGroupsNamesPtr result = groups->GetNames();
return result;
}
}; // TDeprecatedCounterGroups
template <typename T, typename G, typename TL>
TL TDeprecatedCounterGroups<T, G, TL>::Less;
}
static inline IOutputStream& operator<<(IOutputStream& o, const NMonitoring::TDeprecatedCounter& rhs) {
return o << rhs.Val();
}
template <size_t N>
static inline IOutputStream& operator<<(IOutputStream& o, const std::array<NMonitoring::TDeprecatedCounter, N>& rhs) {
for (typename std::array<NMonitoring::TDeprecatedCounter, N>::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
if (!!*it)
o << *it << Endl;
}
return o;
}