TrinityCore
Metric.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef METRIC_H__
19#define METRIC_H__
20
21#include "Define.h"
22#include "Duration.h"
23#include "MPSCQueue.h"
24#include "Optional.h"
25#include <functional>
26#include <iosfwd>
27#include <memory>
28#include <string>
29#include <unordered_map>
30#include <utility>
31#include <variant>
32
33namespace Trinity
34{
35 namespace Asio
36 {
37 class IoContext;
38 class DeadlineTimer;
39 }
40}
41
43{
46};
47
48using MetricTag = std::pair<std::string, std::string>;
49
51{
52 std::string Category;
55
56 // LogValue-specific fields
58
59 // LogEvent-specific fields
60 std::string Title;
61
62 std::string ValueOrEventText;
63
64 // intrusive queue link
65 std::atomic<MetricData*> QueueLink;
66};
67
69{
70private:
71 std::iostream& GetDataStream() { return *_dataStream; }
72 std::unique_ptr<std::iostream> _dataStream;
74 std::unique_ptr<Trinity::Asio::DeadlineTimer> _batchTimer;
75 std::unique_ptr<Trinity::Asio::DeadlineTimer> _overallStatusTimer;
76 int32 _updateInterval = 0;
77 int32 _overallStatusTimerInterval = 0;
78 bool _enabled = false;
79 bool _overallStatusTimerTriggered = false;
80 std::string _hostname;
81 std::string _port;
82 std::string _databaseName;
83 std::function<void()> _overallStatusLogger;
84 std::string _realmName;
85 std::unordered_map<std::string, int64> _thresholds;
86
87 bool Connect();
88 void SendBatch();
89 void ScheduleSend();
90 void ScheduleOverallStatusLog();
91
92 static std::string FormatInfluxDBValue(bool value);
93 template <class T>
94 static std::string FormatInfluxDBValue(T value);
95 static std::string FormatInfluxDBValue(std::string const& value);
96 static std::string FormatInfluxDBValue(char const* value);
97 static std::string FormatInfluxDBValue(double value);
98 static std::string FormatInfluxDBValue(float value);
99 static std::string FormatInfluxDBValue(std::chrono::nanoseconds value);
100
101 static std::string FormatInfluxDBTagValue(std::string const& value);
102
103 // ToDo: should format TagKey and FieldKey too in the same way as TagValue
104
105public:
106 Metric();
107 ~Metric();
108 static Metric* instance();
109
110 void Initialize(std::string const& realmName, Trinity::Asio::IoContext& ioContext, std::function<void()> overallStatusLogger);
111 void LoadFromConfigs();
112 void Update();
113 bool ShouldLog(std::string const& category, int64 value) const;
114
115 template<class T, class... TagsList>
116 void LogValue(std::string category, T value, TagsList&&... tags)
117 {
118 using namespace std::chrono;
119
120 MetricData* data = new MetricData;
121 data->Category = std::move(category);
122 data->Timestamp = system_clock::now();
123 data->Type = METRIC_DATA_VALUE;
124 data->ValueOrEventText = FormatInfluxDBValue(value);
125 if constexpr (sizeof...(tags) > 0)
126 {
127 data->Tags.emplace();
128 if constexpr (sizeof...(tags) > 2)
129 {
130 decltype(auto) tagsVector = data->Tags->emplace<1>();
131 (tagsVector.emplace_back(std::move(tags)), ...);
132 }
133 else
134 {
135 decltype(auto) tagsArray = data->Tags->emplace<0>();
136 tagsArray = { std::move(tags)... };
137 }
138 }
139
140 _queuedData.Enqueue(data);
141 }
142
143 void LogEvent(std::string category, std::string title, std::string description);
144
145 void Unload();
146 bool IsEnabled() const { return _enabled; }
147};
148
149#define sMetric Metric::instance()
150
151template<typename LoggerType>
153{
154public:
155 MetricStopWatch(LoggerType&& loggerFunc) :
156 _logger(std::forward<LoggerType>(loggerFunc)),
157 _startTime(std::chrono::steady_clock::now())
158 {
159 }
160
162 {
164 }
165
166private:
167 LoggerType _logger;
169};
170
171template<typename LoggerType>
173{
174 if (!sMetric->IsEnabled())
175 return {};
176
177 return Optional<MetricStopWatch<LoggerType>>(std::in_place, std::forward<LoggerType>(loggerFunc));
178}
179
180#define TC_METRIC_TAG(name, value) MetricTag(name, value)
181
182#define TC_METRIC_DO_CONCAT(a, b) a ## b
183#define TC_METRIC_CONCAT(a, b) TC_METRIC_DO_CONCAT(a, b)
184#define TC_METRIC_UNIQUE_NAME(name) TC_METRIC_CONCAT(name, __LINE__)
185
186#if defined PERFORMANCE_PROFILING || defined WITHOUT_METRICS
187#define TC_METRIC_EVENT(category, title, description) ((void)0)
188#define TC_METRIC_VALUE(category, value, ...) ((void)0)
189#define TC_METRIC_TIMER(category, ...) ((void)0)
190#define TC_METRIC_DETAILED_EVENT(category, title, description) ((void)0)
191#define TC_METRIC_DETAILED_TIMER(category, ...) ((void)0)
192#define TC_METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) ((void)0)
193#else
194# if TRINITY_PLATFORM != TRINITY_PLATFORM_WINDOWS
195#define TC_METRIC_EVENT(category, title, description) \
196 do { \
197 if (sMetric->IsEnabled()) \
198 sMetric->LogEvent(category, title, description); \
199 } while (0)
200#define TC_METRIC_VALUE(category, value, ...) \
201 do { \
202 if (sMetric->IsEnabled()) \
203 sMetric->LogValue(category, value, ##__VA_ARGS__); \
204 } while (0)
205# else
206#define TC_METRIC_EVENT(category, title, description) \
207 __pragma(warning(push)) \
208 __pragma(warning(disable:4127)) \
209 do { \
210 if (sMetric->IsEnabled()) \
211 sMetric->LogEvent(category, title, description); \
212 } while (0) \
213 __pragma(warning(pop))
214#define TC_METRIC_VALUE(category, value, ...) \
215 __pragma(warning(push)) \
216 __pragma(warning(disable:4127)) \
217 do { \
218 if (sMetric->IsEnabled()) \
219 sMetric->LogValue(category, value, ##__VA_ARGS__); \
220 } while (0) \
221 __pragma(warning(pop))
222# endif
223#define TC_METRIC_TIMER(category, ...) \
224 auto TC_METRIC_UNIQUE_NAME(__tc_metric_stop_watch) = MakeMetricStopWatch([&](TimePoint start) \
225 { \
226 sMetric->LogValue(category, std::chrono::steady_clock::now() - start, ##__VA_ARGS__); \
227 });
228# if defined WITH_DETAILED_METRICS
229#define TC_METRIC_DETAILED_TIMER(category, ...) \
230 auto TC_METRIC_UNIQUE_NAME(__tc_metric_stop_watch) = MakeMetricStopWatch([&](TimePoint start) \
231 { \
232 int64 duration = int64(std::chrono::duration_cast<Milliseconds>(std::chrono::steady_clock::now() - start).count()); \
233 std::string category2 = category; \
234 if (sMetric->ShouldLog(category2, duration)) \
235 sMetric->LogValue(std::move(category2), duration, ##__VA_ARGS__); \
236 });
237#define TC_METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) TC_METRIC_TIMER(category, ##__VA_ARGS__)
238#define TC_METRIC_DETAILED_EVENT(category, title, description) TC_METRIC_EVENT(category, title, description)
239# else
240#define TC_METRIC_DETAILED_EVENT(category, title, description) ((void)0)
241#define TC_METRIC_DETAILED_TIMER(category, ...) ((void)0)
242#define TC_METRIC_DETAILED_NO_THRESHOLD_TIMER(category, ...) ((void)0)
243# endif
244
245#endif
246
247#endif // METRIC_H__
int64_t int64
Definition: Define.h:137
#define TC_COMMON_API
Definition: Define.h:99
int32_t int32
Definition: Define.h:138
std::chrono::system_clock::time_point SystemTimePoint
Definition: Duration.h:42
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition: Duration.h:41
std::conditional_t< IntrusiveLink !=nullptr, Trinity::Impl::MPSCQueueIntrusive< T, IntrusiveLink >, Trinity::Impl::MPSCQueueNonIntrusive< T > > MPSCQueue
Definition: MPSCQueue.h:173
MetricDataType
Definition: Metric.h:43
@ METRIC_DATA_EVENT
Definition: Metric.h:45
@ METRIC_DATA_VALUE
Definition: Metric.h:44
Optional< MetricStopWatch< LoggerType > > MakeMetricStopWatch(LoggerType &&loggerFunc)
Definition: Metric.h:172
std::pair< std::string, std::string > MetricTag
Definition: Metric.h:48
#define sMetric
Definition: Metric.h:149
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
MetricStopWatch(LoggerType &&loggerFunc)
Definition: Metric.h:155
LoggerType _logger
Definition: Metric.h:167
~MetricStopWatch()
Definition: Metric.h:161
TimePoint _startTime
Definition: Metric.h:168
Definition: Metric.h:69
std::string _hostname
Definition: Metric.h:80
std::unique_ptr< std::iostream > _dataStream
Definition: Metric.h:72
std::string _port
Definition: Metric.h:81
std::string _databaseName
Definition: Metric.h:82
std::string _realmName
Definition: Metric.h:84
std::unique_ptr< Trinity::Asio::DeadlineTimer > _overallStatusTimer
Definition: Metric.h:75
std::iostream & GetDataStream()
Definition: Metric.h:71
std::function< void()> _overallStatusLogger
Definition: Metric.h:83
MPSCQueue< MetricData, &MetricData::QueueLink > _queuedData
Definition: Metric.h:73
std::unique_ptr< Trinity::Asio::DeadlineTimer > _batchTimer
Definition: Metric.h:74
bool IsEnabled() const
Definition: Metric.h:146
void LogValue(std::string category, T value, TagsList &&... tags)
Definition: Metric.h:116
std::unordered_map< std::string, int64 > _thresholds
Definition: Metric.h:85
void Update(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:90
STL namespace.
std::string Category
Definition: Metric.h:52
SystemTimePoint Timestamp
Definition: Metric.h:53
std::string Title
Definition: Metric.h:60
std::string ValueOrEventText
Definition: Metric.h:62
Optional< std::variant< std::array< MetricTag, 2 >, std::vector< MetricTag > > > Tags
Definition: Metric.h:57
MetricDataType Type
Definition: Metric.h:54
std::atomic< MetricData * > QueueLink
Definition: Metric.h:65