#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 struct TDeprecatedCountersBase { virtual ~TDeprecatedCountersBase() { } virtual void OutputImpl(IOutputStream&) = 0; static T& Instance() { return *Singleton(); } 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 > class TDeprecatedCounterGroups { public: typedef TMap TGroups; typedef TVector TGroupsNames; typedef THolder 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 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 OldGroups; TSpinLock AddMutex; ui64 Timeout; static TL Less; private: G* Add(const T& name) { TGuard 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 guard(AddMutex); Groups->Free(); delete Groups; Groups = nullptr; typename TList::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 TL TDeprecatedCounterGroups::Less; } static inline IOutputStream& operator<<(IOutputStream& o, const NMonitoring::TDeprecatedCounter& rhs) { return o << rhs.Val(); } template static inline IOutputStream& operator<<(IOutputStream& o, const std::array& rhs) { for (typename std::array::const_iterator it = rhs.begin(); it != rhs.end(); ++it) { if (!!*it) o << *it << Endl; } return o; }