/* * IXCobraMetricsPublisher.h * Author: Benjamin Sergeant * Copyright (c) 2017 Machine Zone. All rights reserved. */ #pragma once #include "IXCobraMetricsThreadedPublisher.h" #include #include #include #include #include namespace ix { class CobraMetricsPublisher { public: CobraMetricsPublisher(); ~CobraMetricsPublisher(); /// Thread safety notes: /// /// 1. _enabled, _blacklist and _rate_control read/writes are not protected by a mutex /// to make shouldPush as fast as possible. _enabled default to false. /// /// The code that set those is ran only once at init, and /// the last value to be set is _enabled, which is also the first value checked in /// shouldPush, so there shouldn't be any race condition. /// /// 2. The queue of messages is thread safe, so multiple metrics can be safely pushed on /// multiple threads /// /// 3. Access to _last_update is protected as it needs to be read/write. /// /// Configuration / set keys, etc... /// All input data but the channel name is encrypted with rc4 void configure(const std::string& appkey, const std::string& endpoint, const std::string& channel, const std::string& rolename, const std::string& rolesecret, bool enablePerMessageDeflate); /// Setter for the list of blacklisted metrics ids. /// That list is sorted internally for fast lookups void setBlacklist(const std::vector& blacklist); /// Set the maximum rate at which a metrics can be sent. Unit is seconds /// if rate_control = { 'foo_id': 60 }, /// the foo_id metric cannot be pushed more than once every 60 seconds void setRateControl(const std::unordered_map& rate_control); /// Configuration / enable/disable void enable(bool enabled); /// Simple interface, list of key value pairs where typeof(key) == typeof(value) == string typedef std::unordered_map Message; void push(const std::string& id, const CobraMetricsPublisher::Message& data = CobraMetricsPublisher::Message()); /// Richer interface using json, which supports types (bool, int, float) and hierarchies of /// elements /// /// The shouldPushTest argument should be set to false, and used in combination with the /// shouldPush method for places where we want to be as lightweight as possible when /// collecting metrics. When set to false, it is used so that we don't do double work when /// computing whether a metrics should be sent or not. void push(const std::string& id, const Json::Value& data, bool shouldPushTest = true); /// Interface used by lua. msg is a json encoded string. void push(const std::string& id, const std::string& data, bool shouldPushTest = true); /// Tells whether a metric can be pushed. /// A metric can be pushed if it satisfies those conditions: /// /// 1. the metrics system should be enabled /// 2. the metrics shouldn't be black-listed /// 3. the metrics shouldn't have reached its rate control limit at this /// "sampling"/"calling" time bool shouldPush(const std::string& id) const; /// Get generic information json object Json::Value& getGenericAttributes(); /// Set generic information values void setGenericAttributes(const std::string& attrName, const Json::Value& value); /// Set a unique id for the session. A uuid can be used. void setSession(const std::string& session) { _session = session; } /// Get the unique id used to identify the current session const std::string& getSession() const { return _session; } /// Return the number of milliseconds since the epoch (~1970) uint64_t getMillisecondsSinceEpoch() const; /// Set satori connection publish mode void setPublishMode(CobraConnectionPublishMode publishMode); /// Flush the publish queue bool flushQueue(); /// Lifecycle management. Free resources when backgrounding void suspend(); void resume(); /// Tells whether the socket connection is opened bool isConnected() const; /// Returns true only if we're authenticated bool isAuthenticated() const; private: /// Lookup an id in our metrics to see whether it is blacklisted /// Complexity is logarithmic bool isMetricBlacklisted(const std::string& id) const; /// Tells whether we should drop a metrics or not as part of an enqueuing /// because it exceed the max update rate (it is sent too often) bool isAboveMaxUpdateRate(const std::string& id) const; /// Record when a metric was last sent. Used for rate control void setLastUpdate(const std::string& id); /// /// Member variables /// CobraMetricsThreadedPublisher _cobra_metrics_theaded_publisher; /// A boolean to enable or disable this system /// push becomes a no-op when _enabled is false std::atomic _enabled; /// A uuid used to uniquely identify a session std::string _session; /// The _device json blob is populated once when configuring this system /// It record generic metadata about the client, run (version, device model, etc...) Json::Value _device; mutable std::mutex _device_mutex; // protect access to _device /// Metrics control (black list + rate control) std::vector _blacklist; std::unordered_map _rate_control; std::unordered_map> _last_update; mutable std::mutex _last_update_mutex; // protect access to _last_update /// Bump a counter for each metric type std::unordered_map _counters; mutable std::mutex _counters_mutex; // protect access to _counters // const strings for internal ids static const std::string kSetRateControlId; static const std::string kSetBlacklistId; /// Our protocol version. Can be used by subscribers who would want to be backward /// compatible if we change the way we arrange data static const int kVersion; }; } // namespace ix