18#ifndef TRINITYCORE_METRIC_H
19#define TRINITYCORE_METRIC_H
29#include <unordered_map>
39using MetricTag = std::pair<std::string, std::string>;
40using MetricTags = std::variant<std::monostate, std::array<MetricTag, 2>, std::vector<MetricTag>>;
71 int32 _overallStatusTimerInterval = 0;
72 bool _enabled =
false;
73 bool _overallStatusTimerTriggered =
false;
79 std::unordered_map<std::string, int64, Trinity::TransparentHash<std::string_view>, std::equal_to<>>
_thresholds;
84 void ScheduleOverallStatusLog();
86 static std::string FormatInfluxDBValue(
bool value);
87 template <
class T>
requires std::integral<T> && (!std::same_as<T, bool>)
88 static std::string FormatInfluxDBValue(T value);
89 static std::string FormatInfluxDBValue(std::string
const& value);
90 static std::string FormatInfluxDBValue(
char const* value);
91 static std::string FormatInfluxDBValue(
double value);
92 static std::string FormatInfluxDBValue(
float value);
93 static std::string FormatInfluxDBValue(std::chrono::nanoseconds value);
95 static std::string FormatInfluxDBTagValue(std::string
const& value);
106 static Metric* instance();
108 void Initialize(std::string
const& realmName,
Trinity::Asio::IoContext& ioContext, std::function<
void()> overallStatusLogger);
109 void LoadFromConfigs();
111 bool ShouldLog(std::string_view category,
int64 value)
const;
113 template<
class T,
class... TagsList>
114 void LogValue(std::string_view category, T value, TagsList&&... tags)
noexcept
116 using TagsType = std::conditional_t<(
sizeof...(tags) > 2),
117 std::vector<MetricTag>,
118 std::conditional_t<(
sizeof...(tags) > 0),
119 std::array<MetricTag, 2>,
125 .Timestamp = std::chrono::system_clock::now(),
127 .Tags =
MetricTags{ std::in_place_type<TagsType> },
128 .ValueOrEventText = FormatInfluxDBValue(value)
130 if constexpr (
sizeof...(tags) > 2)
132 TagsType& tagsVector = std::get<TagsType>(data->
Tags);
133 (tagsVector.emplace_back(std::forward<TagsList>(tags)), ...);
135 else if constexpr (
sizeof...(tags) == 2)
137 [](TagsType& tagsArray,
auto const& tag1,
auto const& tag2)
141 }(std::get<TagsType>(data->
Tags), std::forward<TagsList>(tags)...);
143 else if constexpr (
sizeof...(tags) == 1)
145 [](TagsType& tagsArray,
auto const& tag1)
148 }(std::get<TagsType>(data->
Tags), std::forward<TagsList>(tags)...);
151 _queuedData.Enqueue(data);
154 void LogEvent(std::string_view category, std::string_view title, std::string description);
160#define sMetric Metric::instance()
167 StartTime = std::chrono::steady_clock::now();
174template<
typename LoggerType>
184template<
typename LoggerType>
187#define TC_METRIC_TAG(name, value) std::pair<std::string_view, std::string_view>(name, value)
189#define TC_METRIC_DO_CONCAT(a, b) a ## b
190#define TC_METRIC_CONCAT(a, b) TC_METRIC_DO_CONCAT(a, b)
191#define TC_METRIC_UNIQUE_NAME(name) TC_METRIC_CONCAT(name, __LINE__)
193#if defined PERFORMANCE_PROFILING || defined WITHOUT_METRICS
194#define TC_METRIC_EVENT(category, title, description) ((void)0)
195#define TC_METRIC_VALUE(category, value, ...) ((void)0)
196#define TC_METRIC_TIMER(category, ...) ((void)0)
197#define TC_METRIC_DETAILED_EVENT(category, title, description) ((void)0)
198#define TC_METRIC_DETAILED_TIMER(category, ...) ((void)0)
199#define TC_METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) ((void)0)
201#define TC_METRIC_EVENT(category, title, description) \
203 if (Metric* metric = sMetric; metric->IsEnabled()) \
204 metric->LogEvent(category, title, description); \
206#define TC_METRIC_VALUE(category, value, ...) \
208 if (Metric* metric = sMetric; metric->IsEnabled()) \
209 metric->LogValue(category, value, ## __VA_ARGS__); \
211#define TC_METRIC_TIMER_IMPL(variable, category, ...) \
212 MetricStopWatch variable{ [&](Metric* metric, TimePoint start) \
214 metric->LogValue(category, std::chrono::steady_clock::now() - start, ## __VA_ARGS__); \
218 if (Metric* metric = sMetric; metric->IsEnabled()) \
219 variable.Enable(metric); \
221#define TC_METRIC_TIMER(category, ...) TC_METRIC_TIMER_IMPL(TC_METRIC_UNIQUE_NAME(tc_metric_stop_watch_), category, ## __VA_ARGS__)
222# if defined WITH_DETAILED_METRICS
223#define TC_METRIC_DETAILED_TIMER_IMPL(variable, category, ...) \
224 MetricStopWatch variable{ [&](Metric* metric, TimePoint start) \
226 int64 duration = int64(duration_cast<Milliseconds>(std::chrono::steady_clock::now() - start).count()); \
227 if (metric->ShouldLog(category, duration)) \
228 metric->LogValue(category, duration, ## __VA_ARGS__); \
232 if (Metric* metric = sMetric; metric->IsEnabled()) \
233 variable.Enable(metric); \
235#define TC_METRIC_DETAILED_TIMER(category, ...) TC_METRIC_DETAILED_TIMER_IMPL(TC_METRIC_UNIQUE_NAME(tc_metric_stop_watch_), category, ## __VA_ARGS__)
236#define TC_METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) TC_METRIC_TIMER(category, ## __VA_ARGS__)
237#define TC_METRIC_DETAILED_EVENT(category, title, description) TC_METRIC_EVENT(category, title, description)
239#define TC_METRIC_DETAILED_EVENT(category, title, description) ((void)0)
240#define TC_METRIC_DETAILED_TIMER(category, ...) ((void)0)
241#define TC_METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) ((void)0)
std::chrono::system_clock::time_point SystemTimePoint
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
std::conditional_t< IntrusiveLink !=nullptr, Trinity::Impl::MPSCQueueIntrusive< T, IntrusiveLink >, Trinity::Impl::MPSCQueueNonIntrusive< T > > MPSCQueue
std::pair< std::string, std::string > MetricTag
std::variant< std::monostate, std::array< MetricTag, 2 >, std::vector< MetricTag > > MetricTags
Metric(Metric const &)=delete
std::string _databaseName
Metric & operator=(Metric const &)=delete
std::unique_ptr< Trinity::Asio::DeadlineTimer > _overallStatusTimer
std::function< void()> _overallStatusLogger
std::unique_ptr< iostream > _dataStream
Metric & operator=(Metric &&)=delete
void LogValue(std::string_view category, T value, TagsList &&... tags) noexcept
MPSCQueue< MetricData, &MetricData::QueueLink > _queuedData
std::unordered_map< std::string, int64, Trinity::TransparentHash< std::string_view >, std::equal_to<> > _thresholds
std::unique_ptr< Trinity::Asio::DeadlineTimer > _batchTimer
iostream & GetDataStream()
SystemTimePoint Timestamp
std::string ValueOrEventText
std::atomic< MetricData * > QueueLink
void Enable(Metric *metric) noexcept