/*
* Copyright (C) 2008-2017 TrinityCore
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef METRIC_H__
#define METRIC_H__
#include "Common.h"
#include "Threading/MPSCQueue.h"
#include
#include
#include
enum MetricDataType
{
METRIC_DATA_VALUE,
METRIC_DATA_EVENT
};
struct MetricData
{
std::string Category;
std::chrono::time_point Timestamp;
MetricDataType Type;
// LogValue-specific fields
std::string Value;
// LogEvent-specific fields
std::string Title;
std::string Text;
};
class TC_COMMON_API Metric
{
private:
boost::asio::ip::tcp::iostream _dataStream;
MPSCQueue _queuedData;
std::unique_ptr _batchTimer;
std::unique_ptr _overallStatusTimer;
int32 _updateInterval = 0;
int32 _overallStatusTimerInterval = 0;
bool _enabled = false;
bool _overallStatusTimerTriggered = false;
std::string _hostname;
std::string _port;
std::string _databaseName;
std::function _overallStatusLogger;
std::string _realmName;
bool Connect();
void SendBatch();
void ScheduleSend();
void ScheduleOverallStatusLog();
template::value>::type* = nullptr>
static std::string FormatInfluxDBValue(T value) { return std::to_string(value) + 'i'; }
static std::string FormatInfluxDBValue(std::string const& value)
{
return '"' + boost::replace_all_copy(value, "\"", "\\\"") + '"';
}
static std::string FormatInfluxDBValue(bool value) { return value ? "t" : "f"; }
static std::string FormatInfluxDBValue(const char* value) { return FormatInfluxDBValue(std::string(value)); }
static std::string FormatInfluxDBValue(double value) { return std::to_string(value); }
static std::string FormatInfluxDBValue(float value) { return FormatInfluxDBValue(double(value)); }
static std::string FormatInfluxDBTagValue(std::string const& value)
{
// ToDo: should handle '=' and ',' characters too
return boost::replace_all_copy(value, " ", "\\ ");
}
// ToDo: should format TagKey and FieldKey too in the same way as TagValue
public:
static Metric* instance();
void Initialize(std::string const& realmName, boost::asio::io_service& ioService, std::function overallStatusLogger = [](){});
void LoadFromConfigs();
void Update();
template
void LogValue(std::string const& category, T value)
{
using namespace std::chrono;
MetricData* data = new MetricData;
data->Category = category;
data->Timestamp = system_clock::now();
data->Type = METRIC_DATA_VALUE;
data->Value = FormatInfluxDBValue(value);
_queuedData.Enqueue(data);
}
void LogEvent(std::string const& category, std::string const& title, std::string const& description);
void ForceSend();
bool IsEnabled() const { return _enabled; }
};
#define sMetric Metric::instance()
#if PLATFORM != PLATFORM_WINDOWS
#define TC_METRIC_EVENT(category, title, description) \
do { \
if (sMetric->IsEnabled()) \
sMetric->LogEvent(category, title, description); \
} while (0)
#define TC_METRIC_VALUE(category, value) \
do { \
if (sMetric->IsEnabled()) \
sMetric->LogValue(category, value); \
} while (0)
#else
#define TC_METRIC_EVENT(category, title, description) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { \
if (sMetric->IsEnabled()) \
sMetric->LogEvent(category, title, description); \
} while (0) \
__pragma(warning(pop))
#define TC_METRIC_VALUE(category, value) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { \
if (sMetric->IsEnabled()) \
sMetric->LogValue(category, value); \
} while (0) \
__pragma(warning(pop))
#endif
#endif // METRIC_H__