cobra to statsd bot ported to windows + add unittest
This commit is contained in:
		| @@ -36,6 +36,7 @@ set( IXWEBSOCKET_SOURCES | |||||||
|     ixwebsocket/IXSocketFactory.cpp |     ixwebsocket/IXSocketFactory.cpp | ||||||
|     ixwebsocket/IXSocketServer.cpp |     ixwebsocket/IXSocketServer.cpp | ||||||
|     ixwebsocket/IXSocketTLSOptions.cpp |     ixwebsocket/IXSocketTLSOptions.cpp | ||||||
|  |     ixwebsocket/IXUdpSocket.cpp | ||||||
|     ixwebsocket/IXUrlParser.cpp |     ixwebsocket/IXUrlParser.cpp | ||||||
|     ixwebsocket/IXUserAgent.cpp |     ixwebsocket/IXUserAgent.cpp | ||||||
|     ixwebsocket/IXWebSocket.cpp |     ixwebsocket/IXWebSocket.cpp | ||||||
| @@ -69,6 +70,7 @@ set( IXWEBSOCKET_HEADERS | |||||||
|     ixwebsocket/IXSocketFactory.h |     ixwebsocket/IXSocketFactory.h | ||||||
|     ixwebsocket/IXSocketServer.h |     ixwebsocket/IXSocketServer.h | ||||||
|     ixwebsocket/IXSocketTLSOptions.h |     ixwebsocket/IXSocketTLSOptions.h | ||||||
|  |     ixwebsocket/IXUdpSocket.h | ||||||
|     ixwebsocket/IXUrlParser.h |     ixwebsocket/IXUrlParser.h | ||||||
|     ixwebsocket/IXUtf8Validator.h |     ixwebsocket/IXUtf8Validator.h | ||||||
|     ixwebsocket/IXUserAgent.h |     ixwebsocket/IXUserAgent.h | ||||||
|   | |||||||
| @@ -1,6 +1,10 @@ | |||||||
| # Changelog | # Changelog | ||||||
| All changes to this project will be documented in this file. | All changes to this project will be documented in this file. | ||||||
|  |  | ||||||
|  | ## [8.3.3] - 2020-03-22 | ||||||
|  |  | ||||||
|  | (cobra to statsd) port to windows and add a unittest | ||||||
|  |  | ||||||
| ## [8.3.2] - 2020-03-20 | ## [8.3.2] - 2020-03-20 | ||||||
|  |  | ||||||
| (websocket+tls) fix hang in tls handshake which could lead to ANR, discovered through unittesting. | (websocket+tls) fix hang in tls handshake which could lead to ANR, discovered through unittesting. | ||||||
|   | |||||||
| @@ -7,12 +7,14 @@ set (IXBOTS_SOURCES | |||||||
|     ixbots/IXCobraToSentryBot.cpp |     ixbots/IXCobraToSentryBot.cpp | ||||||
|     ixbots/IXCobraToStatsdBot.cpp |     ixbots/IXCobraToStatsdBot.cpp | ||||||
|     ixbots/IXQueueManager.cpp |     ixbots/IXQueueManager.cpp | ||||||
|  |     ixbots/IXStatsdClient.cpp | ||||||
| ) | ) | ||||||
|  |  | ||||||
| set (IXBOTS_HEADERS | set (IXBOTS_HEADERS | ||||||
|     ixbots/IXCobraToSentryBot.h |     ixbots/IXCobraToSentryBot.h | ||||||
|     ixbots/IXCobraToStatsdBot.h |     ixbots/IXCobraToStatsdBot.h | ||||||
|     ixbots/IXQueueManager.h |     ixbots/IXQueueManager.h | ||||||
|  |     ixbots/IXStatsdClient.h | ||||||
| ) | ) | ||||||
|  |  | ||||||
| add_library(ixbots STATIC | add_library(ixbots STATIC | ||||||
| @@ -30,8 +32,6 @@ if (NOT SPDLOG_FOUND) | |||||||
|   set(SPDLOG_INCLUDE_DIRS ../third_party/spdlog/include) |   set(SPDLOG_INCLUDE_DIRS ../third_party/spdlog/include) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| set(STATSD_CLIENT_INCLUDE_DIRS ../third_party/statsd-client-cpp/src) |  | ||||||
|  |  | ||||||
| set(IXBOTS_INCLUDE_DIRS | set(IXBOTS_INCLUDE_DIRS | ||||||
|     . |     . | ||||||
|     .. |     .. | ||||||
| @@ -39,7 +39,6 @@ set(IXBOTS_INCLUDE_DIRS | |||||||
|     ../ixcobra |     ../ixcobra | ||||||
|     ../ixsentry |     ../ixsentry | ||||||
|     ${JSONCPP_INCLUDE_DIRS} |     ${JSONCPP_INCLUDE_DIRS} | ||||||
|     ${SPDLOG_INCLUDE_DIRS} |     ${SPDLOG_INCLUDE_DIRS}) | ||||||
|     ${STATSD_CLIENT_INCLUDE_DIRS}) |  | ||||||
|  |  | ||||||
| target_include_directories( ixbots PUBLIC ${IXBOTS_INCLUDE_DIRS} ) | target_include_directories( ixbots PUBLIC ${IXBOTS_INCLUDE_DIRS} ) | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| /* | /* | ||||||
|  *  IXCobraToSentryBot.h |  *  IXCobraToSentryBot.h | ||||||
|  *  Author: Benjamin Sergeant |  *  Author: Benjamin Sergeant | ||||||
|  *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |  *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved. | ||||||
|  */ |  */ | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| #include "IXCobraToStatsdBot.h" | #include "IXCobraToStatsdBot.h" | ||||||
| #include "IXQueueManager.h" | #include "IXQueueManager.h" | ||||||
|  | #include "IXStatsdClient.h" | ||||||
|  |  | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <chrono> | #include <chrono> | ||||||
| @@ -16,10 +17,6 @@ | |||||||
| #include <thread> | #include <thread> | ||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| #ifndef _WIN32 |  | ||||||
| #include <statsd_client.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     // fields are command line argument that can be specified multiple times |     // fields are command line argument that can be specified multiple times | ||||||
| @@ -63,11 +60,12 @@ namespace ix | |||||||
|                             const std::string& channel, |                             const std::string& channel, | ||||||
|                             const std::string& filter, |                             const std::string& filter, | ||||||
|                             const std::string& position, |                             const std::string& position, | ||||||
|                             const std::string& host, |                             StatsdClient& statsdClient, | ||||||
|                             int port, |  | ||||||
|                             const std::string& prefix, |  | ||||||
|                             const std::string& fields, |                             const std::string& fields, | ||||||
|                             bool verbose) |                             bool verbose, | ||||||
|  |                             size_t maxQueueSize, | ||||||
|  |                             bool enableHeartbeat, | ||||||
|  |                             int runtime) | ||||||
|     { |     { | ||||||
|         ix::CobraConnection conn; |         ix::CobraConnection conn; | ||||||
|         conn.configure(config); |         conn.configure(config); | ||||||
| @@ -80,11 +78,10 @@ namespace ix | |||||||
|         std::atomic<uint64_t> receivedCount(0); |         std::atomic<uint64_t> receivedCount(0); | ||||||
|         std::atomic<bool> stop(false); |         std::atomic<bool> stop(false); | ||||||
|  |  | ||||||
|         size_t maxQueueSize = 1000; |  | ||||||
|         QueueManager queueManager(maxQueueSize); |         QueueManager queueManager(maxQueueSize); | ||||||
|  |  | ||||||
|         auto timer = [&sentCount, &receivedCount] { |         auto timer = [&sentCount, &receivedCount, &stop] { | ||||||
|             while (true) |             while (!stop) | ||||||
|             { |             { | ||||||
|                 spdlog::info("messages received {} sent {}", receivedCount, sentCount); |                 spdlog::info("messages received {} sent {}", receivedCount, sentCount); | ||||||
|  |  | ||||||
| @@ -95,9 +92,11 @@ namespace ix | |||||||
|  |  | ||||||
|         std::thread t1(timer); |         std::thread t1(timer); | ||||||
|  |  | ||||||
|         auto heartbeat = [&sentCount, &receivedCount] { |         auto heartbeat = [&sentCount, &receivedCount, &enableHeartbeat] { | ||||||
|             std::string state("na"); |             std::string state("na"); | ||||||
|  |  | ||||||
|  |             if (!enableHeartbeat) return; | ||||||
|  |  | ||||||
|             while (true) |             while (true) | ||||||
|             { |             { | ||||||
|                 std::stringstream ss; |                 std::stringstream ss; | ||||||
| @@ -120,21 +119,13 @@ namespace ix | |||||||
|  |  | ||||||
|         std::thread t2(heartbeat); |         std::thread t2(heartbeat); | ||||||
|  |  | ||||||
|         auto statsdSender = [&queueManager, &host, &port, &sentCount, &tokens, &prefix, &stop] { |         auto statsdSender = [&statsdClient, &queueManager, &sentCount, &tokens, &stop] { | ||||||
|             // statsd client |  | ||||||
|             // test with netcat as a server: `nc -ul 8125` |  | ||||||
|             bool statsdBatch = true; |  | ||||||
| #ifndef _WIN32 |  | ||||||
|             statsd::StatsdClient statsdClient(host, port, prefix, statsdBatch); |  | ||||||
| #else |  | ||||||
|             int statsdClient; |  | ||||||
| #endif |  | ||||||
|             while (true) |             while (true) | ||||||
|             { |             { | ||||||
|                 Json::Value msg = queueManager.pop(); |                 Json::Value msg = queueManager.pop(); | ||||||
|  |  | ||||||
|                 if (msg.isNull()) continue; |  | ||||||
|                 if (stop) return; |                 if (stop) return; | ||||||
|  |                 if (msg.isNull()) continue; | ||||||
|  |  | ||||||
|                 std::string id; |                 std::string id; | ||||||
|                 for (auto&& attr : tokens) |                 for (auto&& attr : tokens) | ||||||
| @@ -143,11 +134,8 @@ namespace ix | |||||||
|                     id += extractAttr(attr, msg); |                     id += extractAttr(attr, msg); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 sentCount += 1; |  | ||||||
|  |  | ||||||
| #ifndef _WIN32 |  | ||||||
|                 statsdClient.count(id, 1); |                 statsdClient.count(id, 1); | ||||||
| #endif |                 sentCount += 1; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @@ -214,12 +202,38 @@ namespace ix | |||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|         while (true) |         // Run forever | ||||||
|  |         if (runtime == -1) | ||||||
|         { |         { | ||||||
|             std::chrono::duration<double, std::milli> duration(1000); |             while (true) | ||||||
|             std::this_thread::sleep_for(duration); |             { | ||||||
|  |                 auto duration = std::chrono::seconds(1); | ||||||
|  |                 std::this_thread::sleep_for(duration); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // Run for a duration, used by unittesting now | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             for (int i = 0 ; i < runtime; ++i) | ||||||
|  |             { | ||||||
|  |                 auto duration = std::chrono::seconds(1); | ||||||
|  |                 std::this_thread::sleep_for(duration); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return 0; |         // | ||||||
|  |         // Cleanup. | ||||||
|  |         // join all the bg threads and stop them. | ||||||
|  |         // | ||||||
|  |         conn.disconnect(); | ||||||
|  |         stop = true; | ||||||
|  |  | ||||||
|  |         t1.join(); | ||||||
|  |         if (t2.joinable()) t2.join(); | ||||||
|  |         spdlog::info("heartbeat thread done"); | ||||||
|  |  | ||||||
|  |         t3.join(); | ||||||
|  |  | ||||||
|  |         return (int) sentCount; | ||||||
|     } |     } | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| /* | /* | ||||||
|  *  IXCobraToStatsdBot.h |  *  IXCobraToStatsdBot.h | ||||||
|  *  Author: Benjamin Sergeant |  *  Author: Benjamin Sergeant | ||||||
|  *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |  *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved. | ||||||
|  */ |  */ | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <ixcobra/IXCobraConfig.h> | #include <ixcobra/IXCobraConfig.h> | ||||||
|  | #include <ixbots/IXStatsdClient.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
|  |  | ||||||
| @@ -15,9 +16,10 @@ namespace ix | |||||||
|                             const std::string& channel, |                             const std::string& channel, | ||||||
|                             const std::string& filter, |                             const std::string& filter, | ||||||
|                             const std::string& position, |                             const std::string& position, | ||||||
|                             const std::string& host, |                             StatsdClient& statsdClient, | ||||||
|                             int port, |  | ||||||
|                             const std::string& prefix, |  | ||||||
|                             const std::string& fields, |                             const std::string& fields, | ||||||
|                             bool verbose); |                             bool verbose, | ||||||
|  |                             size_t maxQueueSize, | ||||||
|  |                             bool enableHeartbeat, | ||||||
|  |                             int runtime); | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
							
								
								
									
										154
									
								
								ixbots/ixbots/IXStatsdClient.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								ixbots/ixbots/IXStatsdClient.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2014, Rex | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * * Redistributions of source code must retain the above copyright notice, this | ||||||
|  |  *   list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * * Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *   this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *   and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * * Neither the name of the {organization} nor the names of its | ||||||
|  |  *   contributors may be used to endorse or promote products derived from | ||||||
|  |  *   this software without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||||
|  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
|  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||||
|  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||||
|  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||||
|  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  *  IXStatsdClient.cpp | ||||||
|  |  *  Author: Benjamin Sergeant | ||||||
|  |  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | // Adapted from statsd-client-cpp | ||||||
|  | // test with netcat as a server: `nc -ul 8125` | ||||||
|  |  | ||||||
|  | #include "IXStatsdClient.h" | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | namespace ix | ||||||
|  | { | ||||||
|  |     StatsdClient::StatsdClient(const string& host, | ||||||
|  |                                int port, | ||||||
|  |                                const string& prefix) | ||||||
|  |     : _host(host) | ||||||
|  |       , _port(port) | ||||||
|  |       , _prefix(prefix) | ||||||
|  |       , _stop(false) | ||||||
|  |     { | ||||||
|  |         _thread = std::thread([this] { | ||||||
|  |             while (!_stop) | ||||||
|  |             { | ||||||
|  |                 std::deque<std::string> staged_message_queue; | ||||||
|  |  | ||||||
|  |                 { | ||||||
|  |                     std::lock_guard<std::mutex> lock(_mutex); | ||||||
|  |                     batching_message_queue_.swap(staged_message_queue); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 while (!staged_message_queue.empty()) | ||||||
|  |                 { | ||||||
|  |                     auto message = staged_message_queue.front(); | ||||||
|  |                     _socket.sendto(message); | ||||||
|  |                     staged_message_queue.pop_front(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 std::this_thread::sleep_for(std::chrono::seconds(1)); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     StatsdClient::~StatsdClient() | ||||||
|  |     { | ||||||
|  |         _stop = true; | ||||||
|  |         if (_thread.joinable()) _thread.join(); | ||||||
|  |  | ||||||
|  |         _socket.close(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool StatsdClient::init(std::string& errMsg) | ||||||
|  |     { | ||||||
|  |         return _socket.init(_host, _port, errMsg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* will change the original string */ | ||||||
|  |     void StatsdClient::cleanup(string& key) | ||||||
|  |     { | ||||||
|  |         size_t pos = key.find_first_of(":|@"); | ||||||
|  |         while (pos != string::npos) | ||||||
|  |         { | ||||||
|  |             key[pos] = '_'; | ||||||
|  |             pos = key.find_first_of(":|@"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::dec(const string& key) | ||||||
|  |     { | ||||||
|  |         return count(key, -1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::inc(const string& key) | ||||||
|  |     { | ||||||
|  |         return count(key, 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::count(const string& key, size_t value) | ||||||
|  |     { | ||||||
|  |         return send(key, value, "c"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::gauge(const string& key, size_t value) | ||||||
|  |     { | ||||||
|  |         return send(key, value, "g"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::timing(const string& key, size_t ms) | ||||||
|  |     { | ||||||
|  |         return send(key, ms, "ms"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::send(string key, size_t value, const string &type) | ||||||
|  |     { | ||||||
|  |         cleanup(key); | ||||||
|  |  | ||||||
|  |         char buf[256]; | ||||||
|  |         snprintf(buf, sizeof(buf), "%s%s:%zd|%s", | ||||||
|  |                  _prefix.c_str(), key.c_str(), value, type.c_str()); | ||||||
|  |  | ||||||
|  |         return send(buf); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int StatsdClient::send(const string &message) | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(_mutex); | ||||||
|  |  | ||||||
|  |         if (batching_message_queue_.empty() || | ||||||
|  |             batching_message_queue_.back().length() > max_batching_size) | ||||||
|  |         { | ||||||
|  |             batching_message_queue_.push_back(message); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             (*batching_message_queue_.rbegin()).append("\n").append(message); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } // end namespace ix | ||||||
							
								
								
									
										62
									
								
								ixbots/ixbots/IXStatsdClient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								ixbots/ixbots/IXStatsdClient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | /* | ||||||
|  |  *  IXStatsdClient.h | ||||||
|  |  *  Author: Benjamin Sergeant | ||||||
|  |  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <ixwebsocket/IXNetSystem.h> | ||||||
|  | #include <ixwebsocket/IXUdpSocket.h> | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  | #include <thread> | ||||||
|  | #include <deque> | ||||||
|  | #include <mutex> | ||||||
|  | #include <atomic> | ||||||
|  |  | ||||||
|  | namespace ix { | ||||||
|  |  | ||||||
|  |     class StatsdClient { | ||||||
|  |     public: | ||||||
|  |         StatsdClient(const std::string& host="127.0.0.1", | ||||||
|  |                      int port=8125, | ||||||
|  |                      const std::string& prefix = ""); | ||||||
|  |         ~StatsdClient(); | ||||||
|  |  | ||||||
|  |         bool init(std::string& errMsg); | ||||||
|  |         int inc(const std::string& key); | ||||||
|  |         int dec(const std::string& key); | ||||||
|  |         int count(const std::string& key, size_t value); | ||||||
|  |         int gauge(const std::string& key, size_t value); | ||||||
|  |         int timing(const std::string& key, size_t ms); | ||||||
|  |  | ||||||
|  |     private: | ||||||
|  |         /** | ||||||
|  |          * (Low Level Api) manually send a message | ||||||
|  |          * which might be composed of several lines. | ||||||
|  |          */ | ||||||
|  |         int send(const std::string& message); | ||||||
|  |  | ||||||
|  |         /* (Low Level Api) manually send a message | ||||||
|  |          * type = "c", "g" or "ms" | ||||||
|  |          */ | ||||||
|  |         int send(std::string key, size_t value, const std::string& type); | ||||||
|  |  | ||||||
|  |         void cleanup(std::string& key); | ||||||
|  |  | ||||||
|  |         UdpSocket _socket; | ||||||
|  |  | ||||||
|  |         std::string _host; | ||||||
|  |         int _port; | ||||||
|  |         std::string _prefix; | ||||||
|  |  | ||||||
|  |         std::atomic<bool> _stop; | ||||||
|  |         std::thread _thread; | ||||||
|  |         std::mutex _mutex; // for the queue | ||||||
|  |  | ||||||
|  |         std::deque<std::string> batching_message_queue_; | ||||||
|  |         const uint64_t max_batching_size = 32768; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | } // end namespace ix | ||||||
| @@ -19,6 +19,10 @@ | |||||||
|  |  | ||||||
| #include "IXCobraConfig.h" | #include "IXCobraConfig.h" | ||||||
|  |  | ||||||
|  | #ifdef max | ||||||
|  | #undef max | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     class WebSocket; |     class WebSocket; | ||||||
|   | |||||||
| @@ -66,7 +66,7 @@ namespace ix | |||||||
|         // Virtual methods |         // Virtual methods | ||||||
|         virtual bool accept(std::string& errMsg); |         virtual bool accept(std::string& errMsg); | ||||||
|  |  | ||||||
|         virtual bool connect(const std::string& url, |         virtual bool connect(const std::string& host, | ||||||
|                              int port, |                              int port, | ||||||
|                              std::string& errMsg, |                              std::string& errMsg, | ||||||
|                              const CancellationRequest& isCancellationRequested); |                              const CancellationRequest& isCancellationRequested); | ||||||
|   | |||||||
							
								
								
									
										125
									
								
								ixwebsocket/IXUdpSocket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								ixwebsocket/IXUdpSocket.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | /* | ||||||
|  |  *  IXUdpSocket.cpp | ||||||
|  |  *  Author: Benjamin Sergeant | ||||||
|  |  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "IXUdpSocket.h" | ||||||
|  |  | ||||||
|  | #include "IXNetSystem.h" | ||||||
|  | #include "IXSelectInterrupt.h" | ||||||
|  | #include "IXSelectInterruptFactory.h" | ||||||
|  | #include "IXSocketConnect.h" | ||||||
|  | #include <algorithm> | ||||||
|  | #include <assert.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sstream> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  |  | ||||||
|  | #ifdef min | ||||||
|  | #undef min | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace ix | ||||||
|  | { | ||||||
|  |     UdpSocket::UdpSocket(int fd) | ||||||
|  |         : _sockfd(fd) | ||||||
|  |         , _selectInterrupt(createSelectInterrupt()) | ||||||
|  |     { | ||||||
|  |         ; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     UdpSocket::~UdpSocket() | ||||||
|  |     { | ||||||
|  |         close(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void UdpSocket::close() | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(_socketMutex); | ||||||
|  |  | ||||||
|  |         if (_sockfd == -1) return; | ||||||
|  |  | ||||||
|  |         closeSocket(_sockfd); | ||||||
|  |         _sockfd = -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int UdpSocket::getErrno() | ||||||
|  |     { | ||||||
|  |         int err; | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |         err = WSAGetLastError(); | ||||||
|  | #else | ||||||
|  |         err = errno; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool UdpSocket::isWaitNeeded() | ||||||
|  |     { | ||||||
|  |         int err = getErrno(); | ||||||
|  |  | ||||||
|  |         if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS) | ||||||
|  |         { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void UdpSocket::closeSocket(int fd) | ||||||
|  |     { | ||||||
|  | #ifdef _WIN32 | ||||||
|  |         closesocket(fd); | ||||||
|  | #else | ||||||
|  |         ::close(fd); | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool UdpSocket::init(const std::string& host, int port, std::string& errMsg) | ||||||
|  |     { | ||||||
|  |         _sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | ||||||
|  |         if (_sockfd < 0) | ||||||
|  |         { | ||||||
|  |             errMsg = "Could not create socket"; | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         memset(&_server, 0, sizeof(_server)); | ||||||
|  |         _server.sin_family = AF_INET; | ||||||
|  |         _server.sin_port = htons(port); | ||||||
|  |  | ||||||
|  |         // DNS resolution. | ||||||
|  |         struct addrinfo hints, *result = nullptr; | ||||||
|  |         memset(&hints, 0, sizeof(hints)); | ||||||
|  |         hints.ai_family = AF_INET; | ||||||
|  |         hints.ai_socktype = SOCK_DGRAM; | ||||||
|  |  | ||||||
|  |         int ret = getaddrinfo(host.c_str(), nullptr, &hints, &result); | ||||||
|  |         if (ret != 0) | ||||||
|  |         { | ||||||
|  |             errMsg = strerror(UdpSocket::getErrno()); | ||||||
|  |             freeaddrinfo(result); | ||||||
|  |             close(); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         struct sockaddr_in* host_addr = (struct sockaddr_in*) result->ai_addr; | ||||||
|  |         memcpy(&_server.sin_addr, &host_addr->sin_addr, sizeof(struct in_addr)); | ||||||
|  |         freeaddrinfo(result); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ssize_t UdpSocket::sendto(const std::string& buffer) | ||||||
|  |     { | ||||||
|  |         return (ssize_t)::sendto( | ||||||
|  |             _sockfd, buffer.data(), buffer.size(), 0, (struct sockaddr*) &_server, sizeof(_server)); | ||||||
|  |     } | ||||||
|  | } // namespace ix | ||||||
							
								
								
									
										65
									
								
								ixwebsocket/IXUdpSocket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								ixwebsocket/IXUdpSocket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | /* | ||||||
|  |  *  IXUdpSocket.h | ||||||
|  |  *  Author: Benjamin Sergeant | ||||||
|  |  *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <atomic> | ||||||
|  | #include <functional> | ||||||
|  | #include <memory> | ||||||
|  | #include <mutex> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include <BaseTsd.h> | ||||||
|  | typedef SSIZE_T ssize_t; | ||||||
|  |  | ||||||
|  | #undef EWOULDBLOCK | ||||||
|  | #undef EAGAIN | ||||||
|  | #undef EINPROGRESS | ||||||
|  | #undef EBADF | ||||||
|  | #undef EINVAL | ||||||
|  |  | ||||||
|  | // map to WSA error codes | ||||||
|  | #define EWOULDBLOCK WSAEWOULDBLOCK | ||||||
|  | #define EAGAIN WSATRY_AGAIN | ||||||
|  | #define EINPROGRESS WSAEINPROGRESS | ||||||
|  | #define EBADF WSAEBADF | ||||||
|  | #define EINVAL WSAEINVAL | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "IXCancellationRequest.h" | ||||||
|  | #include "IXNetSystem.h" | ||||||
|  |  | ||||||
|  | namespace ix | ||||||
|  | { | ||||||
|  |     class SelectInterrupt; | ||||||
|  |  | ||||||
|  |     class UdpSocket | ||||||
|  |     { | ||||||
|  |     public: | ||||||
|  |         UdpSocket(int fd = -1); | ||||||
|  |         virtual ~UdpSocket(); | ||||||
|  |  | ||||||
|  |         // Virtual methods | ||||||
|  |         bool init(const std::string& host, int port, std::string& errMsg); | ||||||
|  |         ssize_t sendto(const std::string& buffer); | ||||||
|  |         virtual void close(); | ||||||
|  |  | ||||||
|  |         static int getErrno(); | ||||||
|  |         static bool isWaitNeeded(); | ||||||
|  |         static void closeSocket(int fd); | ||||||
|  |  | ||||||
|  |     protected: | ||||||
|  |         std::atomic<int> _sockfd; | ||||||
|  |         std::mutex _socketMutex; | ||||||
|  |  | ||||||
|  |         struct sockaddr_in _server; | ||||||
|  |  | ||||||
|  |     private: | ||||||
|  |         std::shared_ptr<SelectInterrupt> _selectInterrupt; | ||||||
|  |     }; | ||||||
|  | } // namespace ix | ||||||
| @@ -6,4 +6,4 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #define IX_WEBSOCKET_VERSION "8.3.2" | #define IX_WEBSOCKET_VERSION "8.3.3" | ||||||
|   | |||||||
| @@ -40,31 +40,31 @@ set (SOURCES | |||||||
|   IXGetFreePort.cpp |   IXGetFreePort.cpp | ||||||
|   ../third_party/msgpack11/msgpack11.cpp |   ../third_party/msgpack11/msgpack11.cpp | ||||||
|  |  | ||||||
|   IXSocketTest.cpp |   #IXSocketTest.cpp | ||||||
|   IXSocketConnectTest.cpp |   #IXSocketConnectTest.cpp | ||||||
|   IXWebSocketServerTest.cpp |   #IXWebSocketServerTest.cpp | ||||||
|   IXWebSocketTestConnectionDisconnection.cpp |   #IXWebSocketTestConnectionDisconnection.cpp | ||||||
|   IXUrlParserTest.cpp |   #IXUrlParserTest.cpp | ||||||
|   IXWebSocketServerTest.cpp |   #IXWebSocketServerTest.cpp | ||||||
|   IXHttpClientTest.cpp |   #IXHttpClientTest.cpp | ||||||
|   IXHttpServerTest.cpp |   #IXHttpServerTest.cpp | ||||||
|   IXUnityBuildsTest.cpp |   #IXUnityBuildsTest.cpp | ||||||
|   IXHttpTest.cpp |   #IXHttpTest.cpp | ||||||
|   IXDNSLookupTest.cpp |   #IXDNSLookupTest.cpp | ||||||
|   IXWebSocketSubProtocolTest.cpp |   #IXWebSocketSubProtocolTest.cpp | ||||||
|   IXSentryClientTest.cpp |   #IXSentryClientTest.cpp | ||||||
|   IXWebSocketChatTest.cpp |   #IXWebSocketChatTest.cpp | ||||||
| ) | ) | ||||||
|  |  | ||||||
| # Some unittest don't work on windows yet | # Some unittest don't work on windows yet | ||||||
|  | # Windows without TLS does not have hmac yet | ||||||
| if (UNIX) | if (UNIX) | ||||||
|   list(APPEND SOURCES |   list(APPEND SOURCES | ||||||
|     IXWebSocketCloseTest.cpp |     # IXWebSocketCloseTest.cpp | ||||||
|  |     # IXCobraChatTest.cpp | ||||||
|     # Windows without TLS does not have hmac yet |     # IXCobraMetricsPublisherTest.cpp | ||||||
|     IXCobraChatTest.cpp |     # IXCobraToSentryBotTest.cpp | ||||||
|     IXCobraMetricsPublisherTest.cpp |     IXCobraToStatsdBotTest.cpp | ||||||
|     IXCobraToSentryBotTest.cpp |  | ||||||
|   ) |   ) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| /* | /* | ||||||
|  *  cmd_satori_chat.cpp |  *  IXCobraToSentryTest.cpp | ||||||
|  *  Author: Benjamin Sergeant |  *  Author: Benjamin Sergeant | ||||||
|  *  Copyright (c) 2017 Machine Zone. All rights reserved. |  *  Copyright (c) 2020 Machine Zone. All rights reserved. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "IXTest.h" | #include "IXTest.h" | ||||||
|   | |||||||
							
								
								
									
										141
									
								
								test/IXCobraToStatsdBotTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								test/IXCobraToStatsdBotTest.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | /* | ||||||
|  |  *  IXCobraToStatsdTest.cpp | ||||||
|  |  *  Author: Benjamin Sergeant | ||||||
|  |  *  Copyright (c) 2020 Machine Zone. All rights reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "IXTest.h" | ||||||
|  | #include "catch.hpp" | ||||||
|  | #include <chrono> | ||||||
|  | #include <iostream> | ||||||
|  | #include <ixbots/IXCobraToStatsdBot.h> | ||||||
|  | #include <ixcobra/IXCobraConnection.h> | ||||||
|  | #include <ixcobra/IXCobraMetricsPublisher.h> | ||||||
|  | #include <ixcrypto/IXUuid.h> | ||||||
|  | #include <ixsentry/IXSentryClient.h> | ||||||
|  | #include <ixsnake/IXRedisServer.h> | ||||||
|  | #include <ixsnake/IXSnakeServer.h> | ||||||
|  | #include <ixwebsocket/IXHttpServer.h> | ||||||
|  | #include <ixwebsocket/IXUserAgent.h> | ||||||
|  |  | ||||||
|  | using namespace ix; | ||||||
|  |  | ||||||
|  | namespace | ||||||
|  | { | ||||||
|  |     void runPublisher(const ix::CobraConfig& config, const std::string& channel) | ||||||
|  |     { | ||||||
|  |         ix::CobraMetricsPublisher cobraMetricsPublisher; | ||||||
|  |         cobraMetricsPublisher.configure(config, channel); | ||||||
|  |         cobraMetricsPublisher.setSession(uuid4()); | ||||||
|  |         cobraMetricsPublisher.enable(true); | ||||||
|  |  | ||||||
|  |         Json::Value msg; | ||||||
|  |         msg["fps"] = 60; | ||||||
|  |  | ||||||
|  |         cobraMetricsPublisher.setGenericAttributes("game", "ody"); | ||||||
|  |  | ||||||
|  |         // Wait a bit | ||||||
|  |         ix::msleep(500); | ||||||
|  |  | ||||||
|  |         // publish some messages | ||||||
|  |         cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1) | ||||||
|  |         cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2) | ||||||
|  |         ix::msleep(500); | ||||||
|  |  | ||||||
|  |         cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3) | ||||||
|  |         cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4) | ||||||
|  |         ix::msleep(500); | ||||||
|  |  | ||||||
|  |         cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4) | ||||||
|  |         cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5) | ||||||
|  |         ix::msleep(500); | ||||||
|  |     } | ||||||
|  | } // namespace | ||||||
|  |  | ||||||
|  | TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]") | ||||||
|  | { | ||||||
|  |     SECTION("Exchange and count sent/received messages.") | ||||||
|  |     { | ||||||
|  |         int port = getFreePort(); | ||||||
|  |         snake::AppConfig appConfig = makeSnakeServerConfig(port, true); | ||||||
|  |  | ||||||
|  |         // Start a redis server | ||||||
|  |         ix::RedisServer redisServer(appConfig.redisPort); | ||||||
|  |         auto res = redisServer.listen(); | ||||||
|  |         REQUIRE(res.first); | ||||||
|  |         redisServer.start(); | ||||||
|  |  | ||||||
|  |         // Start a snake server | ||||||
|  |         snake::SnakeServer snakeServer(appConfig); | ||||||
|  |         snakeServer.run(); | ||||||
|  |  | ||||||
|  |         // Start a fake statsd server (ultimately) | ||||||
|  |  | ||||||
|  |         // Run the bot for a small amount of time | ||||||
|  |         std::string channel = ix::generateSessionId(); | ||||||
|  |         std::string appkey("FC2F10139A2BAc53BB72D9db967b024f"); | ||||||
|  |         std::string role = "_sub"; | ||||||
|  |         std::string secret = "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba"; | ||||||
|  |         std::string endpoint = makeCobraEndpoint(port, true); | ||||||
|  |  | ||||||
|  |         ix::CobraConfig config; | ||||||
|  |         config.endpoint = endpoint; | ||||||
|  |         config.appkey = appkey; | ||||||
|  |         config.rolename = role; | ||||||
|  |         config.rolesecret = secret; | ||||||
|  |         config.socketTLSOptions = makeClientTLSOptions(); | ||||||
|  |  | ||||||
|  |         std::thread publisherThread(runPublisher, config, channel); | ||||||
|  |  | ||||||
|  |         std::string filter; | ||||||
|  |         std::string position("$"); | ||||||
|  |         bool verbose = true; | ||||||
|  |         size_t maxQueueSize = 10; | ||||||
|  |         bool enableHeartbeat = false; | ||||||
|  |  | ||||||
|  |         // Only run the bot for 3 seconds | ||||||
|  |         int runtime = 3; | ||||||
|  |  | ||||||
|  |         std::string hostname("127.0.0.1"); | ||||||
|  |         // std::string hostname("www.google.com"); | ||||||
|  |         int statsdPort = 8125; | ||||||
|  |         std::string prefix("ix.test"); | ||||||
|  |         StatsdClient statsdClient(hostname, statsdPort, prefix); | ||||||
|  |  | ||||||
|  |         std::string errMsg; | ||||||
|  |         bool initialized = statsdClient.init(errMsg); | ||||||
|  |         if (!initialized) | ||||||
|  |         { | ||||||
|  |             spdlog::error(errMsg); | ||||||
|  |         } | ||||||
|  |         REQUIRE(initialized); | ||||||
|  |  | ||||||
|  |         std::string fields("device.game\ndevice.os_name"); | ||||||
|  |  | ||||||
|  |         int sentCount = ix::cobra_to_statsd_bot(config, | ||||||
|  |                                                 channel, | ||||||
|  |                                                 filter, | ||||||
|  |                                                 position, | ||||||
|  |                                                 statsdClient, | ||||||
|  |                                                 fields, | ||||||
|  |                                                 verbose, | ||||||
|  |                                                 maxQueueSize, | ||||||
|  |                                                 enableHeartbeat, | ||||||
|  |                                                 runtime); | ||||||
|  |         // | ||||||
|  |         // We want at least 2 messages to be sent | ||||||
|  |         // | ||||||
|  |         REQUIRE(sentCount >= 2); | ||||||
|  |  | ||||||
|  |         // Give us 1s for all messages to be received | ||||||
|  |         ix::msleep(1000); | ||||||
|  |  | ||||||
|  |         spdlog::info("Stopping snake server..."); | ||||||
|  |         snakeServer.stop(); | ||||||
|  |  | ||||||
|  |         spdlog::info("Stopping redis server..."); | ||||||
|  |         redisServer.stop(); | ||||||
|  |  | ||||||
|  |         publisherThread.join(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								third_party/statsd-client-cpp/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								third_party/statsd-client-cpp/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,13 +0,0 @@ | |||||||
| # Compiled Object files |  | ||||||
| *.slo |  | ||||||
| *.lo |  | ||||||
| *.o |  | ||||||
|  |  | ||||||
| # Compiled Dynamic libraries |  | ||||||
| *.so |  | ||||||
| *.dylib |  | ||||||
|  |  | ||||||
| # Compiled Static libraries |  | ||||||
| *.lai |  | ||||||
| *.la |  | ||||||
| *.a |  | ||||||
							
								
								
									
										18
									
								
								third_party/statsd-client-cpp/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								third_party/statsd-client-cpp/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,18 +0,0 @@ | |||||||
| cmake_minimum_required(VERSION 3.1) |  | ||||||
| project(helloCLion) |  | ||||||
|  |  | ||||||
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") |  | ||||||
|  |  | ||||||
| include_directories( |  | ||||||
|     src |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| add_library(statsdcppclient STATIC src/statsd_client.cpp) |  | ||||||
| add_definitions("-fPIC") |  | ||||||
| target_link_libraries(statsdcppclient pthread) |  | ||||||
|  |  | ||||||
| add_executable(system_monitor demo/system_monitor.cpp) |  | ||||||
| target_link_libraries(system_monitor statsdcppclient) |  | ||||||
|  |  | ||||||
| add_executable(test_client demo/test_client.cpp) |  | ||||||
| target_link_libraries(test_client statsdcppclient) |  | ||||||
							
								
								
									
										27
									
								
								third_party/statsd-client-cpp/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								third_party/statsd-client-cpp/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | |||||||
| Copyright (c) 2014, Rex |  | ||||||
| All rights reserved. |  | ||||||
|  |  | ||||||
| Redistribution and use in source and binary forms, with or without |  | ||||||
| modification, are permitted provided that the following conditions are met: |  | ||||||
|  |  | ||||||
| * Redistributions of source code must retain the above copyright notice, this |  | ||||||
|   list of conditions and the following disclaimer. |  | ||||||
|  |  | ||||||
| * Redistributions in binary form must reproduce the above copyright notice, |  | ||||||
|   this list of conditions and the following disclaimer in the documentation |  | ||||||
|   and/or other materials provided with the distribution. |  | ||||||
|  |  | ||||||
| * Neither the name of the {organization} nor the names of its |  | ||||||
|   contributors may be used to endorse or promote products derived from |  | ||||||
|   this software without specific prior written permission. |  | ||||||
|  |  | ||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |  | ||||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |  | ||||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |  | ||||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |  | ||||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |  | ||||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |  | ||||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |  | ||||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |  | ||||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |  | ||||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
							
								
								
									
										34
									
								
								third_party/statsd-client-cpp/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								third_party/statsd-client-cpp/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,34 +0,0 @@ | |||||||
| # a client sdk for StatsD, written in C++ |  | ||||||
|  |  | ||||||
| ## API |  | ||||||
| See [header file](src/statsd_client.h) for more api detail. |  | ||||||
|  |  | ||||||
| ** Notice: this client is not thread-safe ** |  | ||||||
|  |  | ||||||
| ## Demo |  | ||||||
| ### test\_client |  | ||||||
| This simple demo shows how the use this client. |  | ||||||
|  |  | ||||||
| ### system\_monitor |  | ||||||
| This is a daemon for monitoring a Linux system. |  | ||||||
| It'll wake up every minute and monitor the following: |  | ||||||
|  |  | ||||||
| * load |  | ||||||
| * cpu |  | ||||||
| * free memory |  | ||||||
| * free swap (disabled) |  | ||||||
| * received bytes |  | ||||||
| * transmitted bytes |  | ||||||
| * procs |  | ||||||
| * uptime |  | ||||||
|  |  | ||||||
| The stats sent to statsd will be in "host.MACAddress" namespace. |  | ||||||
|  |  | ||||||
| Usage: |  | ||||||
|  |  | ||||||
|     system_monitor statsd-host interface-to-monitor |  | ||||||
|  |  | ||||||
| e.g. |  | ||||||
|  |  | ||||||
|     `system_monitor 172.16.42.1 eth0` |  | ||||||
|  |  | ||||||
| @@ -1,164 +0,0 @@ | |||||||
|  |  | ||||||
| #include <sys/types.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <signal.h> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <netdb.h> |  | ||||||
| #include <sys/sysinfo.h> |  | ||||||
|  |  | ||||||
| #include <sys/ioctl.h> |  | ||||||
| #include <netinet/in.h> |  | ||||||
| #include <net/if.h> |  | ||||||
| #include <string> |  | ||||||
| #include <vector> |  | ||||||
|  |  | ||||||
| #include "statsd_client.h" |  | ||||||
|  |  | ||||||
| using namespace std; |  | ||||||
|  |  | ||||||
| static int running = 1; |  | ||||||
|  |  | ||||||
| void sigterm(int sig) |  | ||||||
| { |  | ||||||
|     running = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| string localhost() { |  | ||||||
|     struct addrinfo hints, *info, *p; |  | ||||||
|     string hostname(1024, '\0'); |  | ||||||
|     gethostname((char*)hostname.data(), hostname.capacity()); |  | ||||||
|  |  | ||||||
|     memset(&hints, 0, sizeof hints); |  | ||||||
|     hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/ |  | ||||||
|     hints.ai_socktype = SOCK_STREAM; |  | ||||||
|     hints.ai_flags = AI_CANONNAME; |  | ||||||
|  |  | ||||||
|     if ( getaddrinfo(hostname.c_str(), "http", &hints, &info) == 0) { |  | ||||||
|         for(p = info; p != NULL; p = p->ai_next) { |  | ||||||
|             hostname = p->ai_canonname; |  | ||||||
|         } |  | ||||||
|         freeaddrinfo(info); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     string::size_type pos = hostname.find("."); |  | ||||||
|     while ( pos != string::npos ) |  | ||||||
|     { |  | ||||||
|         hostname[pos] = '_'; |  | ||||||
|         pos = hostname.find(".", pos); |  | ||||||
|     } |  | ||||||
|     return hostname; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vector<string>& StringSplitTrim(const string& sData, |  | ||||||
|         const string& sDelim, vector<string>& vItems) |  | ||||||
| { |  | ||||||
|     vItems.clear(); |  | ||||||
|  |  | ||||||
|     string::size_type bpos = 0; |  | ||||||
|     string::size_type epos = 0; |  | ||||||
|     string::size_type nlen = sDelim.size(); |  | ||||||
|  |  | ||||||
|     while(sData.substr(epos,nlen) == sDelim) |  | ||||||
|     { |  | ||||||
|         epos += nlen; |  | ||||||
|     } |  | ||||||
|     bpos = epos; |  | ||||||
|  |  | ||||||
|     while ((epos=sData.find(sDelim, epos)) != string::npos) |  | ||||||
|     { |  | ||||||
|         vItems.push_back(sData.substr(bpos, epos-bpos)); |  | ||||||
|         epos += nlen; |  | ||||||
|         while(sData.substr(epos,nlen) == sDelim) |  | ||||||
|         { |  | ||||||
|             epos += nlen; |  | ||||||
|         } |  | ||||||
|         bpos = epos; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(bpos != sData.size()) |  | ||||||
|     { |  | ||||||
|         vItems.push_back(sData.substr(bpos, sData.size()-bpos)); |  | ||||||
|     } |  | ||||||
|     return vItems; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) |  | ||||||
| { |  | ||||||
|     FILE *net, *stat; |  | ||||||
|     struct sysinfo si; |  | ||||||
|     char line[256]; |  | ||||||
|     unsigned int user, nice, sys, idle, total, busy, old_total=0, old_busy=0; |  | ||||||
|  |  | ||||||
|     if (argc != 3) { |  | ||||||
|         printf( "Usage: %s host port\n" |  | ||||||
|                 "Eg:    %s 127.0.0.1 8125\n", |  | ||||||
|                 argv[0], argv[0]); |  | ||||||
|         exit(1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     signal(SIGHUP, SIG_IGN); |  | ||||||
|     signal(SIGPIPE, SIG_IGN); |  | ||||||
|     signal(SIGCHLD, SIG_IGN); /* will save one syscall per sleep */ |  | ||||||
|     signal(SIGTERM, sigterm); |  | ||||||
|  |  | ||||||
|     if ( (net = fopen("/proc/net/dev", "r")) == NULL) { |  | ||||||
|         perror("fopen"); |  | ||||||
|         exit(-1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if ( (stat = fopen("/proc/stat", "r")) == NULL) { |  | ||||||
|         perror("fopen"); |  | ||||||
|         exit(-1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     string ns = string("host.") + localhost().c_str() + "."; |  | ||||||
|     statsd::StatsdClient client(argv[1], atoi(argv[2]), ns); |  | ||||||
|  |  | ||||||
|     daemon(0,0); |  | ||||||
|     printf("running in background.\n"); |  | ||||||
|  |  | ||||||
|     while(running) { |  | ||||||
|         rewind(net); |  | ||||||
|         vector<string> items; |  | ||||||
|         while(!feof(net)) { |  | ||||||
|             fgets(line, sizeof(line), net); |  | ||||||
|             StringSplitTrim(line, " ", items); |  | ||||||
|  |  | ||||||
|             if ( items.size() < 17 ) continue; |  | ||||||
|             if ( items[0].find(":") == string::npos ) continue; |  | ||||||
|             if ( items[1] == "0" and items[9] == "0" ) continue; |  | ||||||
|  |  | ||||||
|             string netface = "network."+items[0].erase( items[0].find(":") ); |  | ||||||
|             client.count( netface+".receive.bytes", atoll(items[1].c_str()) ); |  | ||||||
|             client.count( netface+".receive.packets", atoll(items[2].c_str()) ); |  | ||||||
|             client.count( netface+".transmit.bytes", atoll(items[9].c_str()) ); |  | ||||||
|             client.count( netface+".transmit.packets", atoll(items[10].c_str()) ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         sysinfo(&si); |  | ||||||
|         client.gauge("system.load", 100*si.loads[0]/0x10000); |  | ||||||
|         client.gauge("system.freemem", si.freeram/1024); |  | ||||||
|         client.gauge("system.procs", si.procs); |  | ||||||
|         client.count("system.uptime", si.uptime); |  | ||||||
|  |  | ||||||
|         /* rewind doesn't do the trick for /proc/stat */ |  | ||||||
|         freopen("/proc/stat", "r", stat); |  | ||||||
|         fgets(line, sizeof(line), stat); |  | ||||||
|         sscanf(line, "cpu  %u %u %u %u", &user, &nice, &sys, &idle); |  | ||||||
|         total = user + sys + idle; |  | ||||||
|         busy = user + sys; |  | ||||||
|  |  | ||||||
|         client.send("system.cpu", 100 * (busy - old_busy)/(total - old_total), "g", 1.0); |  | ||||||
|  |  | ||||||
|         old_total = total; |  | ||||||
|         old_busy = busy; |  | ||||||
|         sleep(6); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fclose(net); |  | ||||||
|     fclose(stat); |  | ||||||
|  |  | ||||||
|     exit(0); |  | ||||||
| } |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
|  |  | ||||||
| #include <iostream> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include "statsd_client.h" |  | ||||||
|  |  | ||||||
| int main(void) |  | ||||||
| { |  | ||||||
|     std::cout << "running..." << std::endl; |  | ||||||
|  |  | ||||||
|     statsd::StatsdClient client; |  | ||||||
|     statsd::StatsdClient client2("127.0.0.1", 8125, "myproject.abx.", true); |  | ||||||
|  |  | ||||||
|     client.count("count1", 123, 1.0); |  | ||||||
|     client.count("count2", 125, 1.0); |  | ||||||
|     client.gauge("speed", 10); |  | ||||||
|     int i; |  | ||||||
|     for (i=0; i<1000; i++) |  | ||||||
|         client2.timing("request", i); |  | ||||||
|     sleep(1); |  | ||||||
|     client.inc("count1", 1.0); |  | ||||||
|     client2.dec("count2", 1.0); |  | ||||||
| //    for(i=0; i<1000; i++) { |  | ||||||
| //        client2.count("count3", i, 0.8); |  | ||||||
| //    } |  | ||||||
|  |  | ||||||
|     std::cout << "done" << std::endl; |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
							
								
								
									
										245
									
								
								third_party/statsd-client-cpp/src/statsd_client.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										245
									
								
								third_party/statsd-client-cpp/src/statsd_client.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,245 +0,0 @@ | |||||||
| #include <math.h> |  | ||||||
| #include <netdb.h> |  | ||||||
| #include <time.h> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <netinet/in.h> |  | ||||||
| #include "statsd_client.h" |  | ||||||
|  |  | ||||||
| using namespace std; |  | ||||||
| namespace statsd { |  | ||||||
|  |  | ||||||
| inline bool fequal(float a, float b) |  | ||||||
| { |  | ||||||
|     const float epsilon = 0.0001; |  | ||||||
|     return ( fabs(a - b) < epsilon ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline bool should_send(float sample_rate) |  | ||||||
| { |  | ||||||
|     if ( fequal(sample_rate, 1.0) ) |  | ||||||
|     { |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     float p = ((float)random() / RAND_MAX); |  | ||||||
|     return sample_rate > p; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct _StatsdClientData { |  | ||||||
|     int     sock; |  | ||||||
|     struct  sockaddr_in server; |  | ||||||
|  |  | ||||||
|     string  ns; |  | ||||||
|     string  host; |  | ||||||
|     short   port; |  | ||||||
|     bool    init; |  | ||||||
|  |  | ||||||
|     char    errmsg[1024]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| StatsdClient::StatsdClient(const string& host, |  | ||||||
|                            int port, |  | ||||||
|                            const string& ns, |  | ||||||
|                            const bool batching) |  | ||||||
| : batching_(batching), exit_(false) |  | ||||||
| { |  | ||||||
|     d = new _StatsdClientData; |  | ||||||
|     d->sock = -1; |  | ||||||
|     config(host, port, ns); |  | ||||||
|     srandom((unsigned) time(NULL)); |  | ||||||
|  |  | ||||||
|     if (batching_) { |  | ||||||
|         pthread_mutex_init(&batching_mutex_lock_, nullptr); |  | ||||||
|         batching_thread_ = std::thread([this] { |  | ||||||
|           while (!exit_) { |  | ||||||
|               std::deque<std::string> staged_message_queue; |  | ||||||
|  |  | ||||||
|               pthread_mutex_lock(&batching_mutex_lock_); |  | ||||||
|               batching_message_queue_.swap(staged_message_queue); |  | ||||||
|               pthread_mutex_unlock(&batching_mutex_lock_); |  | ||||||
|  |  | ||||||
|               while(!staged_message_queue.empty()) { |  | ||||||
|                   send_to_daemon(staged_message_queue.front()); |  | ||||||
|                   staged_message_queue.pop_front(); |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               std::this_thread::sleep_for(std::chrono::milliseconds(1000)); |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| StatsdClient::~StatsdClient() |  | ||||||
| { |  | ||||||
|     if (batching_) { |  | ||||||
|         exit_ = true; |  | ||||||
|         batching_thread_.join(); |  | ||||||
|         pthread_mutex_destroy(&batching_mutex_lock_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     // close socket |  | ||||||
|     if (d->sock >= 0) { |  | ||||||
|         close(d->sock); |  | ||||||
|         d->sock = -1; |  | ||||||
|         delete d; |  | ||||||
|         d = NULL; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void StatsdClient::config(const string& host, int port, const string& ns) |  | ||||||
| { |  | ||||||
|     d->ns = ns; |  | ||||||
|     d->host = host; |  | ||||||
|     d->port = port; |  | ||||||
|     d->init = false; |  | ||||||
|     if ( d->sock >= 0 ) { |  | ||||||
|         close(d->sock); |  | ||||||
|     } |  | ||||||
|     d->sock = -1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::init() |  | ||||||
| { |  | ||||||
|     if ( d->init ) return 0; |  | ||||||
|  |  | ||||||
|     d->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |  | ||||||
|     if ( d->sock == -1 ) { |  | ||||||
|         snprintf(d->errmsg, sizeof(d->errmsg), "could not create socket, err=%s", strerror(errno)); |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     memset(&d->server, 0, sizeof(d->server)); |  | ||||||
|     d->server.sin_family = AF_INET; |  | ||||||
|     d->server.sin_port = htons(d->port); |  | ||||||
|  |  | ||||||
|     int ret = inet_aton(d->host.c_str(), &d->server.sin_addr); |  | ||||||
|     if ( ret == 0 ) |  | ||||||
|     { |  | ||||||
|         // host must be a domain, get it from internet |  | ||||||
|         struct addrinfo hints, *result = NULL; |  | ||||||
|         memset(&hints, 0, sizeof(hints)); |  | ||||||
|         hints.ai_family = AF_INET; |  | ||||||
|         hints.ai_socktype = SOCK_DGRAM; |  | ||||||
|  |  | ||||||
|         ret = getaddrinfo(d->host.c_str(), NULL, &hints, &result); |  | ||||||
|         if ( ret ) { |  | ||||||
|             close(d->sock); |  | ||||||
|             d->sock = -1; |  | ||||||
|             snprintf(d->errmsg, sizeof(d->errmsg), |  | ||||||
|                      "getaddrinfo fail, error=%d, msg=%s", ret, gai_strerror(ret) ); |  | ||||||
|             return -2; |  | ||||||
|         } |  | ||||||
|         struct sockaddr_in* host_addr = (struct sockaddr_in*)result->ai_addr; |  | ||||||
|         memcpy(&d->server.sin_addr, &host_addr->sin_addr, sizeof(struct in_addr)); |  | ||||||
|         freeaddrinfo(result); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     d->init = true; |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* will change the original string */ |  | ||||||
| void StatsdClient::cleanup(string& key) |  | ||||||
| { |  | ||||||
|     size_t pos = key.find_first_of(":|@"); |  | ||||||
|     while ( pos != string::npos ) |  | ||||||
|     { |  | ||||||
|         key[pos] = '_'; |  | ||||||
|         pos = key.find_first_of(":|@"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::dec(const string& key, float sample_rate) |  | ||||||
| { |  | ||||||
|     return count(key, -1, sample_rate); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::inc(const string& key, float sample_rate) |  | ||||||
| { |  | ||||||
|     return count(key, 1, sample_rate); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::count(const string& key, size_t value, float sample_rate) |  | ||||||
| { |  | ||||||
|     return send(key, value, "c", sample_rate); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::gauge(const string& key, size_t value, float sample_rate) |  | ||||||
| { |  | ||||||
|     return send(key, value, "g", sample_rate); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::timing(const string& key, size_t ms, float sample_rate) |  | ||||||
| { |  | ||||||
|     return send(key, ms, "ms", sample_rate); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::send(string key, size_t value, const string &type, float sample_rate) |  | ||||||
| { |  | ||||||
|     if (!should_send(sample_rate)) { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     cleanup(key); |  | ||||||
|  |  | ||||||
|     char buf[256]; |  | ||||||
|     if ( fequal( sample_rate, 1.0 ) ) |  | ||||||
|     { |  | ||||||
|         snprintf(buf, sizeof(buf), "%s%s:%zd|%s", |  | ||||||
|                  d->ns.c_str(), key.c_str(), value, type.c_str()); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         snprintf(buf, sizeof(buf), "%s%s:%zd|%s|@%.2f", |  | ||||||
|                  d->ns.c_str(), key.c_str(), value, type.c_str(), sample_rate); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return send(buf); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int StatsdClient::send(const string &message) |  | ||||||
| { |  | ||||||
|     if (batching_) { |  | ||||||
|         pthread_mutex_lock(&batching_mutex_lock_); |  | ||||||
|         if (batching_message_queue_.empty() || |  | ||||||
|             batching_message_queue_.back().length() > max_batching_size) { |  | ||||||
|             batching_message_queue_.push_back(message); |  | ||||||
|         } else { |  | ||||||
|             (*batching_message_queue_.rbegin()).append("\n").append(message); |  | ||||||
|         } |  | ||||||
|         pthread_mutex_unlock(&batching_mutex_lock_); |  | ||||||
|  |  | ||||||
|         return 0; |  | ||||||
|     } else { |  | ||||||
|         return send_to_daemon(message); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int StatsdClient::send_to_daemon(const string &message) { |  | ||||||
|     int ret = init(); |  | ||||||
|     if ( ret ) |  | ||||||
|     { |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
|     ret = (int) sendto(d->sock, message.data(), message.size(), 0, (struct sockaddr *) &d->server, sizeof(d->server)); |  | ||||||
|     if ( ret == -1) { |  | ||||||
|         snprintf(d->errmsg, sizeof(d->errmsg), |  | ||||||
|                  "sendto server fail, host=%s:%d, err=%s", d->host.c_str(), d->port, strerror(errno)); |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const char* StatsdClient::errmsg() |  | ||||||
| { |  | ||||||
|     return d->errmsg; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,66 +0,0 @@ | |||||||
|  |  | ||||||
| #ifndef STATSD_CLIENT_H |  | ||||||
| #define STATSD_CLIENT_H |  | ||||||
|  |  | ||||||
| #include <sys/types.h> |  | ||||||
| #include <arpa/inet.h> |  | ||||||
| #include <sys/socket.h> |  | ||||||
| #include <pthread.h> |  | ||||||
| #include <string> |  | ||||||
| #include <thread> |  | ||||||
| #include <deque> |  | ||||||
| #include <iostream> |  | ||||||
|  |  | ||||||
| namespace statsd { |  | ||||||
|  |  | ||||||
| struct _StatsdClientData; |  | ||||||
|  |  | ||||||
| class StatsdClient { |  | ||||||
| public: |  | ||||||
|     StatsdClient(const std::string& host="127.0.0.1", int port=8125, const std::string& ns = "", const bool batching = false); |  | ||||||
|     ~StatsdClient(); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
|     // you can config at anytime; client will use new address (useful for Singleton) |  | ||||||
|     void config(const std::string& host, int port, const std::string& ns = ""); |  | ||||||
|     const char* errmsg(); |  | ||||||
|     int send_to_daemon(const std::string &); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
|     int inc(const std::string& key, float sample_rate = 1.0); |  | ||||||
|     int dec(const std::string& key, float sample_rate = 1.0); |  | ||||||
|     int count(const std::string& key, size_t value, float sample_rate = 1.0); |  | ||||||
|     int gauge(const std::string& key, size_t value, float sample_rate = 1.0); |  | ||||||
|     int timing(const std::string& key, size_t ms, float sample_rate = 1.0); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
|     /** |  | ||||||
|      * (Low Level Api) manually send a message |  | ||||||
|      * which might be composed of several lines. |  | ||||||
|      */ |  | ||||||
|     int send(const std::string& message); |  | ||||||
|  |  | ||||||
|     /* (Low Level Api) manually send a message |  | ||||||
|      * type = "c", "g" or "ms" |  | ||||||
|      */ |  | ||||||
|     int send(std::string key, size_t value, |  | ||||||
|              const std::string& type, float sample_rate); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
|     int init(); |  | ||||||
|     void cleanup(std::string& key); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
|     struct _StatsdClientData* d; |  | ||||||
|  |  | ||||||
|     bool batching_; |  | ||||||
|     bool exit_; |  | ||||||
|     pthread_mutex_t batching_mutex_lock_; |  | ||||||
|     std::thread batching_thread_; |  | ||||||
|     std::deque<std::string> batching_message_queue_; |  | ||||||
|     const uint64_t max_batching_size = 32768; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| } // end namespace |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										22
									
								
								third_party/zlib/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								third_party/zlib/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -225,25 +225,3 @@ endif() | |||||||
| if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) | if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) | ||||||
|     install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") |     install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| #============================================================================ |  | ||||||
| # Example binaries |  | ||||||
| #============================================================================ |  | ||||||
|  |  | ||||||
| add_executable(example test/example.c) |  | ||||||
| target_link_libraries(example zlib) |  | ||||||
| add_test(example example) |  | ||||||
|  |  | ||||||
| add_executable(minigzip test/minigzip.c) |  | ||||||
| target_link_libraries(minigzip zlib) |  | ||||||
|  |  | ||||||
| if(HAVE_OFF64_T) |  | ||||||
|     add_executable(example64 test/example.c) |  | ||||||
|     target_link_libraries(example64 zlib) |  | ||||||
|     set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") |  | ||||||
|     add_test(example64 example64) |  | ||||||
|  |  | ||||||
|     add_executable(minigzip64 test/minigzip.c) |  | ||||||
|     target_link_libraries(minigzip64 zlib) |  | ||||||
|     set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") |  | ||||||
| endif() |  | ||||||
|   | |||||||
| @@ -21,16 +21,11 @@ option(USE_TLS "Add TLS support" ON) | |||||||
| include_directories(ws .) | include_directories(ws .) | ||||||
| include_directories(ws ..) | include_directories(ws ..) | ||||||
| include_directories(ws ../third_party) | include_directories(ws ../third_party) | ||||||
| include_directories(ws ../third_party/statsd-client-cpp/src) |  | ||||||
| include_directories(ws ../third_party/spdlog/include) | include_directories(ws ../third_party/spdlog/include) | ||||||
| include_directories(ws ../third_party/cpp-linenoise) | include_directories(ws ../third_party/cpp-linenoise) | ||||||
|  |  | ||||||
| add_definitions(-DSPDLOG_COMPILED_LIB=1) | add_definitions(-DSPDLOG_COMPILED_LIB=1) | ||||||
|  |  | ||||||
| if (UNIX) |  | ||||||
|   set( STATSD_CLIENT_SOURCES ../third_party/statsd-client-cpp/src/statsd_client.cpp) |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| find_package(JsonCpp) | find_package(JsonCpp) | ||||||
| if (NOT JSONCPP_FOUND) | if (NOT JSONCPP_FOUND) | ||||||
|   include_directories(../third_party/jsoncpp) |   include_directories(../third_party/jsoncpp) | ||||||
| @@ -39,7 +34,6 @@ endif() | |||||||
|  |  | ||||||
| add_executable(ws | add_executable(ws | ||||||
|   ../third_party/msgpack11/msgpack11.cpp |   ../third_party/msgpack11/msgpack11.cpp | ||||||
|   ${STATSD_CLIENT_SOURCES} |  | ||||||
|   ${JSONCPP_SOURCES} |   ${JSONCPP_SOURCES} | ||||||
|  |  | ||||||
|   ws_http_client.cpp |   ws_http_client.cpp | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -269,6 +269,9 @@ int main(int argc, char** argv) | |||||||
|     cobra2statsd->add_option("--pidfile", pidfile, "Pid file"); |     cobra2statsd->add_option("--pidfile", pidfile, "Pid file"); | ||||||
|     cobra2statsd->add_option("--filter", filter, "Stream SQL Filter"); |     cobra2statsd->add_option("--filter", filter, "Stream SQL Filter"); | ||||||
|     cobra2statsd->add_option("--position", position, "Stream position"); |     cobra2statsd->add_option("--position", position, "Stream position"); | ||||||
|  |     cobra2statsd->add_option("--queue_size", | ||||||
|  |                              maxQueueSize, | ||||||
|  |                              "Size of the queue to hold messages before they are sent to Sentry"); | ||||||
|     addTLSOptions(cobra2statsd); |     addTLSOptions(cobra2statsd); | ||||||
|     addCobraConfig(cobra2statsd); |     addCobraConfig(cobra2statsd); | ||||||
|  |  | ||||||
| @@ -450,8 +453,20 @@ int main(int argc, char** argv) | |||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("cobra_to_statsd")) |     else if (app.got_subcommand("cobra_to_statsd")) | ||||||
|     { |     { | ||||||
|         ret = ix::cobra_to_statsd_bot( |         bool enableHeartbeat = true; | ||||||
|             cobraConfig, channel, filter, position, hostname, statsdPort, prefix, fields, verbose); |         int runtime = -1; | ||||||
|  |         ix::StatsdClient statsdClient(hostname, statsdPort, prefix); | ||||||
|  |  | ||||||
|  |         ret = ix::cobra_to_statsd_bot(cobraConfig, | ||||||
|  |                                       channel, | ||||||
|  |                                       filter, | ||||||
|  |                                       position, | ||||||
|  |                                       statsdClient, | ||||||
|  |                                       fields, | ||||||
|  |                                       verbose, | ||||||
|  |                                       maxQueueSize, | ||||||
|  |                                       enableHeartbeat, | ||||||
|  |                                       runtime); | ||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("cobra_to_sentry")) |     else if (app.got_subcommand("cobra_to_sentry")) | ||||||
|     { |     { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user