From 81be8e2e69bcb00b4fa26df7b6178d0c02b4d1e6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Mon, 27 Jul 2020 23:13:07 +0000 Subject: [PATCH 01/37] Add base HTTP server files --- .../ext/http/server/HttpServer.h | 895 ++++++++++++++++++ .../ext/http/server/SocketTools.h | 861 +++++++++++++++++ 2 files changed, 1756 insertions(+) create mode 100644 ext/include/opentelemetry/ext/http/server/HttpServer.h create mode 100644 ext/include/opentelemetry/ext/http/server/SocketTools.h diff --git a/ext/include/opentelemetry/ext/http/server/HttpServer.h b/ext/include/opentelemetry/ext/http/server/HttpServer.h new file mode 100644 index 0000000000..de6e93e5eb --- /dev/null +++ b/ext/include/opentelemetry/ext/http/server/HttpServer.h @@ -0,0 +1,895 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "SocketTools.h" + +#ifdef HAVE_HTTP_DEBUG +# ifdef LOG_TRACE +# undef LOG_TRACE +# define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) +# endif +#endif + +#ifndef HTTP_SERVER_NS +# define HTTP_SERVER_NS testing +#endif + +namespace HTTP_SERVER_NS +{ + +constexpr const char *CONTENT_TYPE = "Content-Type"; +constexpr const char *CONTENT_TYPE_TEXT = "text/plain"; +constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; + +struct HttpRequest +{ + std::string client; + std::string method; + std::string uri; + std::string protocol; + std::map headers; + std::string content; +}; + +struct HttpResponse +{ + int code; + std::string message; + std::map headers; + std::string body; +}; + +using CallbackFunction = std::function; + +class HttpRequestCallback +{ +protected: + CallbackFunction callback = nullptr; + +public: + HttpRequestCallback(){}; + + HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; }; + + HttpRequestCallback(CallbackFunction func) : callback(func){}; + + HttpRequestCallback &operator=(CallbackFunction func) + { + callback = func; + return (*this); + } + + virtual int onHttpRequest(HttpRequest const &request, HttpResponse &response) + { + if (callback != nullptr) + { + return callback(request, response); + } + return 0; + }; +}; + +// Simple HTTP server +// Goals: +// - Support enough of HTTP to be used as a mock +// - Be flexible to allow creating various test scenarios +// Out of scope: +// - Performance +// - Full support of RFC 7230-7237 +class HttpServer : private SocketTools::Reactor::SocketCallback +{ + +protected: + struct Connection + { + SocketTools::Socket socket; + std::string receiveBuffer; + std::string sendBuffer; + enum + { + Idle, + ReceivingHeaders, + Sending100Continue, + ReceivingBody, + Processing, + SendingHeaders, + SendingBody, + Closing + } state; + size_t contentLength; + bool keepalive; + HttpRequest request; + HttpResponse response; + }; + + std::string m_serverHost; + bool allowKeepalive{true}; + SocketTools::Reactor m_reactor; + std::list m_listeningSockets; + + class HttpRequestHandler : public std::pair + { + + public: + HttpRequestHandler(std::string key, HttpRequestCallback *value) + { + first = key; + second = value; + }; + + HttpRequestHandler() : std::pair() + { + first = ""; + second = nullptr; + }; + + HttpRequestHandler &operator=(std::pair other) + { + first = other.first; + second = other.second; + return (*this); + }; + + HttpRequestHandler &operator=(HttpRequestCallback &cb) + { + second = &cb; + return (*this); + }; + + HttpRequestHandler &operator=(HttpRequestCallback *cb) + { + second = cb; + return (*this); + }; + }; + + std::list m_handlers; + + std::map m_connections; + size_t m_maxRequestHeadersSize, m_maxRequestContentSize; + +public: + void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; } + + HttpServer() + : m_serverHost("unnamed"), + allowKeepalive(true), + m_reactor(*this), + m_maxRequestHeadersSize(8192), + m_maxRequestContentSize(2 * 1024 * 1024){}; + + HttpServer(std::string serverHost, int port = 30000) : HttpServer() + { + std::ostringstream os; + os << serverHost << ":" << port; + setServerName(os.str()); + addListeningPort(port); + }; + + ~HttpServer() + { + for (auto &sock : m_listeningSockets) + { + sock.close(); + } + } + + void setRequestLimits(size_t maxRequestHeadersSize, size_t maxRequestContentSize) + { + m_maxRequestHeadersSize = maxRequestHeadersSize; + m_maxRequestContentSize = maxRequestContentSize; + } + + void setServerName(std::string const &name) { m_serverHost = name; } + + int addListeningPort(int port) + { + SocketTools::Socket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + socket.setNonBlocking(); + socket.setReuseAddr(); + + SocketTools::SocketAddr addr(0, port); + socket.bind(addr); + socket.getsockname(addr); + + socket.listen(10); + m_listeningSockets.push_back(socket); + m_reactor.addSocket(socket, SocketTools::Reactor::Acceptable); + LOG_INFO("HttpServer: Listening on %s", addr.toString().c_str()); + + return addr.port(); + } + + HttpRequestHandler &addHandler(const std::string &root, HttpRequestCallback &handler) + { + // No thread-safety here! + m_handlers.push_back({root, &handler}); + LOG_INFO("HttpServer: Added handler for %s", root.c_str()); + return m_handlers.back(); + } + + HttpRequestHandler &operator[](const std::string &root) + { + // No thread-safety here! + m_handlers.push_back({root, nullptr}); + LOG_INFO("HttpServer: Added handler for %s", root.c_str()); + return m_handlers.back(); + } + + HttpServer &operator+=( std::pair other) + { + LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); + m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); + return (*this); + }; + + void start() + { + m_reactor.start(); + } + + void stop() + { + m_reactor.stop(); + } + +protected: + virtual void onSocketAcceptable(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: accepting socket fd=0x%llx", socket.m_sock); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) != + m_listeningSockets.end()); + + SocketTools::Socket csocket; + SocketTools::SocketAddr caddr; + if (socket.accept(csocket, caddr)) + { + csocket.setNonBlocking(); + Connection &conn = m_connections[csocket]; + conn.socket = csocket; + conn.state = Connection::Idle; + conn.request.client = caddr.toString(); + m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + LOG_TRACE("HttpServer: [%s] accepted", conn.request.client.c_str()); + } + } + + virtual void onSocketReadable(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: reading socket fd=0x%llx", socket.m_sock); + // No thread-safety here! + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); + + // No thread-safety here! + auto connIt = m_connections.find(socket); + if (connIt == m_connections.end()) + { + return; + } + Connection &conn = connIt->second; + + char buffer[2048] = {0}; + int received = socket.recv(buffer, sizeof(buffer)); + LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), received); + if (received <= 0) + { + handleConnectionClosed(conn); + return; + } + conn.receiveBuffer.append(buffer, buffer + received); + + handleConnection(conn); + } + + virtual void onSocketWritable(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: writing socket fd=0x%llx", socket.m_sock); + + // No thread-safety here! + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); + + // No thread-safety here! + auto connIt = m_connections.find(socket); + if (connIt == m_connections.end()) + { + return; + } + Connection &conn = connIt->second; + + if (!sendMore(conn)) + { + handleConnection(conn); + } + } + + virtual void onSocketClosed(SocketTools::Socket socket) override + { + LOG_TRACE("HttpServer: closing socket fd=0x%llx", socket.m_sock); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); + + auto connIt = m_connections.find(socket); + if (connIt == m_connections.end()) + { + return; + } + Connection &conn = connIt->second; + + handleConnectionClosed(conn); + } + + bool sendMore(Connection &conn) + { + if (conn.sendBuffer.empty()) + { + return false; + } + + int sent = conn.socket.send(conn.sendBuffer.data(), static_cast(conn.sendBuffer.size())); + LOG_TRACE("HttpServer: [%s] sent %d", conn.request.client.c_str(), sent); + if (sent < 0 && conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) + { + return true; + } + conn.sendBuffer.erase(0, sent); + + if (!conn.sendBuffer.empty()) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Writable | SocketTools::Reactor::Closed); + return true; + } + + return false; + } + +protected: + void handleConnectionClosed(Connection &conn) + { + LOG_TRACE("HttpServer: [%s] closed", conn.request.client.c_str()); + if (conn.state != Connection::Idle && conn.state != Connection::Closing) + { + LOG_WARN("HttpServer: [%s] connection closed unexpectedly", conn.request.client.c_str()); + } + m_reactor.removeSocket(conn.socket); + auto connIt = m_connections.find(conn.socket); + conn.socket.close(); + m_connections.erase(connIt); + } + + void handleConnection(Connection &conn) + { + for (;;) + { + if (conn.state == Connection::Idle) + { + conn.response.code = 0; + conn.state = Connection::ReceivingHeaders; + LOG_TRACE("HttpServer: [%s] receiving headers", conn.request.client.c_str()); + } + + if (conn.state == Connection::ReceivingHeaders) + { + bool lfOnly = false; + size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); + if (ofs == std::string::npos) + { + lfOnly = true; + ofs = conn.receiveBuffer.find("\n\n"); + } + size_t headersLen = (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); + if (headersLen > m_maxRequestHeadersSize) + { + LOG_WARN("HttpServer: [%s] headers too long - %u", conn.request.client.c_str(), + static_cast(headersLen)); + conn.response.code = 431; // Request Header Fields Too Large + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + if (ofs == std::string::npos) + { + return; + } + + if (!parseHeaders(conn)) + { + LOG_WARN("HttpServer: [%s] invalid headers", conn.request.client.c_str()); + conn.response.code = 400; // Bad Request + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + LOG_INFO("HttpServer: [%s] %s %s %s", conn.request.client.c_str(), + conn.request.method.c_str(), conn.request.uri.c_str(), + conn.request.protocol.c_str()); + conn.receiveBuffer.erase(0, ofs + (lfOnly ? 2 : 4)); + + conn.keepalive = (conn.request.protocol == "HTTP/1.1"); + auto const connection = conn.request.headers.find("Connection"); + if (connection != conn.request.headers.end()) + { + if (equalsLowercased(connection->second, "keep-alive")) + { + conn.keepalive = true; + } + else if (equalsLowercased(connection->second, "close")) + { + conn.keepalive = false; + } + } + + auto const contentLength = conn.request.headers.find("Content-Length"); + if (contentLength != conn.request.headers.end()) + { + conn.contentLength = atoi(contentLength->second.c_str()); + } + else + { + conn.contentLength = 0; + } + if (conn.contentLength > m_maxRequestContentSize) + { + LOG_WARN("HttpServer: [%s] content too long - %u", conn.request.client.c_str(), + static_cast(conn.contentLength)); + conn.response.code = 413; // Payload Too Large + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + + auto const expect = conn.request.headers.find("Expect"); + if (expect != conn.request.headers.end() && conn.request.protocol == "HTTP/1.1") + { + if (!equalsLowercased(expect->second, "100-continue")) + { + LOG_WARN("HttpServer: [%s] unknown expectation - %s", conn.request.client.c_str(), + expect->second.c_str()); + conn.response.code = 417; // Expectation Failed + conn.keepalive = false; + conn.state = Connection::Processing; + continue; + } + conn.sendBuffer = "HTTP/1.1 100 Continue\r\n\r\n"; + conn.state = Connection::Sending100Continue; + LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", conn.request.client.c_str()); + continue; + } + + conn.state = Connection::ReceivingBody; + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + } + + if (conn.state == Connection::Sending100Continue) + { + if (sendMore(conn)) + { + return; + } + + conn.state = Connection::ReceivingBody; + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + } + + if (conn.state == Connection::ReceivingBody) + { + if (conn.receiveBuffer.length() < conn.contentLength) + { + return; + } + + if (conn.receiveBuffer.length() == conn.contentLength) + { + conn.request.content = std::move(conn.receiveBuffer); + conn.receiveBuffer.clear(); + } + else + { + conn.request.content.assign(conn.receiveBuffer, 0, conn.contentLength); + conn.receiveBuffer.erase(0, conn.contentLength); + } + + conn.state = Connection::Processing; + LOG_TRACE("HttpServer: [%s] processing request", conn.request.client.c_str()); + } + + if (conn.state == Connection::Processing) + { + processRequest(conn); + + std::ostringstream os; + os << conn.request.protocol << ' ' << conn.response.code << ' ' << conn.response.message + << "\r\n"; + for (auto const &header : conn.response.headers) + { + os << header.first << ": " << header.second << "\r\n"; + } + os << "\r\n"; + + conn.sendBuffer = os.str(); + conn.state = Connection::SendingHeaders; + LOG_TRACE("HttpServer: [%s] sending headers", conn.request.client.c_str()); + } + + if (conn.state == Connection::SendingHeaders) + { + if (sendMore(conn)) + { + return; + } + + conn.sendBuffer = std::move(conn.response.body); + conn.state = Connection::SendingBody; + LOG_TRACE("HttpServer: [%s] sending body", conn.request.client.c_str()); + } + + if (conn.state == Connection::SendingBody) + { + if (sendMore(conn)) + { + return; + } + + conn.keepalive &= allowKeepalive; + + if (conn.keepalive) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + conn.state = Connection::Idle; + LOG_TRACE("HttpServer: [%s] idle (keep-alive)", conn.request.client.c_str()); + if (conn.receiveBuffer.empty()) + { + return; + } + } + else + { + conn.socket.shutdown(SocketTools::Socket::ShutdownSend); + m_reactor.addSocket(conn.socket, SocketTools::Reactor::Closed); + conn.state = Connection::Closing; + LOG_TRACE("HttpServer: [%s] closing", conn.request.client.c_str()); + } + } + + if (conn.state == Connection::Closing) + { + return; + } + } + } + + bool parseHeaders(Connection &conn) + { + // Method + char const *begin = conn.receiveBuffer.c_str(); + char const *ptr = begin; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != ' ') + { + return false; + } + conn.request.method.assign(begin, ptr); + while (*ptr == ' ') + { + ptr++; + } + + // URI + begin = ptr; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != ' ') + { + return false; + } + conn.request.uri.assign(begin, ptr); + while (*ptr == ' ') + { + ptr++; + } + + // Protocol + begin = ptr; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != '\r' && *ptr != '\n') + { + return false; + } + conn.request.protocol.assign(begin, ptr); + if (*ptr == '\r') + { + ptr++; + } + if (*ptr != '\n') + { + return false; + } + ptr++; + + // Headers + conn.request.headers.clear(); + while (*ptr != '\r' && *ptr != '\n') + { + // Name + begin = ptr; + while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + if (*ptr != ':') + { + return false; + } + std::string name = normalizeHeaderName(begin, ptr); + ptr++; + while (*ptr == ' ') + { + ptr++; + } + + // Value + begin = ptr; + while (*ptr && *ptr != '\r' && *ptr != '\n') + { + ptr++; + } + conn.request.headers[name] = std::string(begin, ptr); + if (*ptr == '\r') + { + ptr++; + } + if (*ptr != '\n') + { + return false; + } + ptr++; + } + + if (*ptr == '\r') + { + ptr++; + } + if (*ptr != '\n') + { + return false; + } + ptr++; + + return true; + } + + static bool equalsLowercased(std::string const &str, char const *mask) + { + char const *ptr = str.c_str(); + while (*ptr && *mask && ::tolower(*ptr) == *mask) + { + ptr++; + mask++; + } + return !*ptr && !*mask; + } + + static std::string normalizeHeaderName(char const *begin, char const *end) + { + std::string result(begin, end); + bool first = true; + for (char &ch : result) + { + if (first) + { + ch = static_cast(::toupper(ch)); + first = false; + } + else if (ch == '-') + { + first = true; + } + else + { + ch = static_cast(::tolower(ch)); + } + } + return result; + } + + void processRequest(Connection &conn) + { + conn.response.message.clear(); + conn.response.headers.clear(); + conn.response.body.clear(); + + if (conn.response.code == 0) + { + conn.response.code = 404; // Not Found + for (auto &handler : m_handlers) + { + if (conn.request.uri.length() >= handler.first.length() && + strncmp(conn.request.uri.c_str(), handler.first.c_str(), handler.first.length()) == 0) + { + LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), + handler.first.c_str()); + auto callback = handler.second; + int result = handler.second->onHttpRequest(conn.request, conn.response); + if (result != 0) + { + conn.response.code = result; + break; + } + } + } + + if (conn.response.code == -1) + { + LOG_TRACE("HttpServer: [%s] closing by request", conn.request.client.c_str()); + handleConnectionClosed(conn); + } + } + + if (conn.response.message.empty()) + { + conn.response.message = getDefaultResponseMessage(conn.response.code); + } + + conn.response.headers["Host"] = m_serverHost; + conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); + conn.response.headers["Date"] = formatTimestamp(time(nullptr)); + conn.response.headers["Content-Length"] = std::to_string(conn.response.body.size()); + } + + static std::string formatTimestamp(time_t time) + { + tm tm; +#ifdef _WIN32 + gmtime_s(&tm, &time); +#else + gmtime_r(&time, &tm); +#endif + char buf[32]; + strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", &tm); + return buf; + } + +public: + + static char const *getDefaultResponseMessage(int code) + { + switch (code) + { + // *INDENT-OFF* + case 100: + return "Continue"; + case 101: + return "Switching Protocols"; + case 200: + return "OK"; + case 201: + return "Created"; + case 202: + return "Accepted"; + case 203: + return "Non-Authoritative Information"; + case 204: + return "No Content"; + case 205: + return "Reset Content"; + case 206: + return "Partial Content"; + case 300: + return "Multiple Choices"; + case 301: + return "Moved Permanently"; + case 302: + return "Found"; + case 303: + return "See Other"; + case 304: + return "Not Modified"; + case 305: + return "Use Proxy"; + case 306: + return "Switch Proxy"; + case 307: + return "Temporary Redirect"; + case 308: + return "Permanent Redirect"; + case 400: + return "Bad Request"; + case 401: + return "Unauthorized"; + case 402: + return "Payment Required"; + case 403: + return "Forbidden"; + case 404: + return "Not Found"; + case 405: + return "Method Not Allowed"; + case 406: + return "Not Acceptable"; + case 407: + return "Proxy Authentication Required"; + case 408: + return "Request Timeout"; + case 409: + return "Conflict"; + case 410: + return "Gone"; + case 411: + return "Length Required"; + case 412: + return "Precondition Failed"; + case 413: + return "Payload Too Large"; + case 414: + return "URI Too Long"; + case 415: + return "Unsupported Media Type"; + case 416: + return "Range Not Satisfiable"; + case 417: + return "Expectation Failed"; + case 421: + return "Misdirected Request"; + case 426: + return "Upgrade Required"; + case 428: + return "Precondition Required"; + case 429: + return "Too Many Requests"; + case 431: + return "Request Header Fields Too Large"; + case 500: + return "Internal Server Error"; + case 501: + return "Not Implemented"; + case 502: + return "Bad Gateway"; + case 503: + return "Service Unavailable"; + case 504: + return "Gateway Timeout"; + case 505: + return "HTTP Version Not Supported"; + case 506: + return "Variant Also Negotiates"; + case 510: + return "Not Extended"; + case 511: + return "Network Authentication Required"; + default: + return "???"; + // *INDENT-ON* + } + } +}; + +} // namespace HTTP_SERVER_NS + diff --git a/ext/include/opentelemetry/ext/http/server/SocketTools.h b/ext/include/opentelemetry/ext/http/server/SocketTools.h new file mode 100644 index 0000000000..1cdc8a6881 --- /dev/null +++ b/ext/include/opentelemetry/ext/http/server/SocketTools.h @@ -0,0 +1,861 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +//# include + +# include + +// TODO: consider NOMINMAX +# undef min +# undef max +# pragma comment(lib, "ws2_32.lib") + +#else + +# include + +# ifdef __linux__ +# include +# endif + +# if __APPLE__ +# include "TargetConditionals.h" +// Use kqueue on mac +# include +# include +# include +# endif + +// Common POSIX headers for Linux and Mac OS X +# include +# include +# include +# include +# include +# include + +#endif + +#ifndef _Out_cap_ +# define _Out_cap_(size) +#endif + +#if defined(HAVE_CONSOLE_LOG) && !defined(LOG_DEBUG) +// Log to console if there's no standard log facility defined +# include +# ifndef LOG_DEBUG +# define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# endif +#endif + +#ifndef LOG_DEBUG +// Don't log anything if there's no standard log facility defined +# define LOG_DEBUG(fmt_, ...) +# define LOG_TRACE(fmt_, ...) +# define LOG_INFO(fmt_, ...) +# define LOG_WARN(fmt_, ...) +# define LOG_ERROR(fmt_, ...) +#endif + +namespace common +{ + +/// +/// A simple thread, derived class overloads onThread() method. +/// +struct Thread +{ + + std::thread m_thread; + + volatile bool m_terminate{false}; + + /// + /// Thread Constructor + /// + /// Thread + Thread() {} + + /// + /// Start Thread + /// + void startThread() + { + m_terminate = false; + m_thread = std::thread([&]() { this->onThread(); }); + } + + /// + /// Join Thread + /// + void joinThread() + { + m_terminate = true; + if (m_thread.joinable()) + { + m_thread.join(); + } + } + + /// + /// Indicates if this thread should terminate + /// + /// + bool shouldTerminate() const { return m_terminate; } + + /// + /// Must be implemented by children + /// + virtual void onThread() = 0; + + /// + /// Thread destructor + /// + /// + virtual ~Thread() noexcept {} +}; + +}; // namespace common +namespace SocketTools +{ + +#ifdef _WIN32 +// WinSocks need extra (de)initialization, solved by a global object here, +// whose constructor/destructor will be called before and after main(). +struct WsaInitializer +{ + + WsaInitializer() + { + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); + } + + ~WsaInitializer() { WSACleanup(); } +}; + +static WsaInitializer g_wsaInitializer; + +#endif + +/// +/// Encapsulation of sockaddr(_in) +/// +struct SocketAddr +{ + static u_long const Loopback = 0x7F000001; + + sockaddr m_data; + + /// + /// SocketAddr constructor + /// + /// SocketAddr + SocketAddr() { memset(&m_data, 0, sizeof(m_data)); } + + SocketAddr(u_long addr, int port) + { + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(static_cast(port)); + inet4.sin_addr.s_addr = htonl(addr); + } + + SocketAddr(char const *addr) + { +#ifdef _WIN32 + INT addrlen = sizeof(m_data); + WCHAR buf[200]; + for (int i = 0; i < sizeof(buf) && addr[i]; i++) + { + buf[i] = addr[i]; + } + buf[199] = L'\0'; + ::WSAStringToAddressW(buf, AF_INET, nullptr, &m_data, &addrlen); +#else + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + char const *colon = strchr(addr, ':'); + if (colon) + { + inet4.sin_port = htons(atoi(colon + 1)); + char buf[16]; + memcpy(buf, addr, std::min(15, colon - addr)); + buf[15] = '\0'; + ::inet_pton(AF_INET, buf, &inet4.sin_addr); + } + else + { + inet4.sin_port = 0; + ::inet_pton(AF_INET, addr, &inet4.sin_addr); + } +#endif + } + + SocketAddr(SocketAddr const &other) = default; + + SocketAddr &operator=(SocketAddr const &other) = default; + + operator sockaddr *() { return &m_data; } + + operator const sockaddr *() const { return &m_data; } + + int port() const + { + switch (m_data.sa_family) + { + case AF_INET: { + sockaddr_in const &inet4 = reinterpret_cast(m_data); + return ntohs(inet4.sin_port); + } + + default: + return -1; + } + } + + std::string toString() const + { + std::ostringstream os; + + switch (m_data.sa_family) + { + case AF_INET: { + sockaddr_in const &inet4 = reinterpret_cast(m_data); + u_long addr = ntohl(inet4.sin_addr.s_addr); + os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.' + << (addr & 255); + os << ':' << ntohs(inet4.sin_port); + break; + } + + default: + os << "[?AF?" << m_data.sa_family << ']'; + } + return os.str(); + } +}; + +/// +/// Encapsulation of a socket (non-exclusive ownership) +/// +struct Socket +{ + +#ifdef _WIN32 + typedef SOCKET Type; + static Type const Invalid = INVALID_SOCKET; +#else + typedef int Type; + static Type const Invalid = -1; +#endif + + Type m_sock; + + Socket(Type sock = Invalid) : m_sock(sock) {} + + Socket(int af, int type, int proto) { m_sock = ::socket(af, type, proto); } + + ~Socket() {} + + operator Socket::Type() const { return m_sock; } + + bool operator==(Socket const &other) const { return (m_sock == other.m_sock); } + + bool operator!=(Socket const &other) const { return (m_sock != other.m_sock); } + + bool operator<(Socket const &other) const { return (m_sock < other.m_sock); } + + bool invalid() const { return (m_sock == Invalid); } + + void setNonBlocking() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + u_long value = 1; + ::ioctlsocket(m_sock, FIONBIO, &value); +#else + int flags = ::fcntl(m_sock, F_GETFL, 0); + ::fcntl(m_sock, F_SETFL, flags | O_NONBLOCK); +#endif + } + + bool setReuseAddr() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + BOOL value = TRUE; +#else + int value = 1; +#endif + return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), + sizeof(value)) == 0); + } + + bool setNoDelay() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + BOOL value = TRUE; +#else + int value = 1; +#endif + return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&value), + sizeof(value)) == 0); + } + + bool connect(SocketAddr const &addr) + { + assert(m_sock != Invalid); + return (::connect(m_sock, addr, sizeof(addr)) == 0); + } + + void close() + { + assert(m_sock != Invalid); +#ifdef _WIN32 + ::closesocket(m_sock); +#else + ::close(m_sock); +#endif + m_sock = Invalid; + } + + int recv(_Out_cap_(size) void *buffer, unsigned size) + { + assert(m_sock != Invalid); + int flags = 0; + return static_cast(::recv(m_sock, reinterpret_cast(buffer), size, flags)); + } + + int send(void const *buffer, unsigned size) + { + assert(m_sock != Invalid); + return static_cast(::send(m_sock, reinterpret_cast(buffer), size, 0)); + } + + bool bind(SocketAddr const &addr) + { + assert(m_sock != Invalid); + return (::bind(m_sock, addr, sizeof(addr)) == 0); + } + + bool getsockname(SocketAddr &addr) const + { + assert(m_sock != Invalid); +#ifdef _WIN32 + int addrlen = sizeof(addr); +#else + socklen_t addrlen = sizeof(addr); +#endif + return (::getsockname(m_sock, addr, &addrlen) == 0); + } + + bool listen(int backlog) + { + assert(m_sock != Invalid); + return (::listen(m_sock, backlog) == 0); + } + + bool accept(Socket &csock, SocketAddr &caddr) + { + assert(m_sock != Invalid); +#ifdef _WIN32 + int addrlen = sizeof(caddr); +#else + socklen_t addrlen = sizeof(caddr); +#endif + csock = ::accept(m_sock, caddr, &addrlen); + return !csock.invalid(); + } + + bool shutdown(int how) + { + assert(m_sock != Invalid); + return (::shutdown(m_sock, how) == 0); + } + + int error() const + { +#ifdef _WIN32 + return ::WSAGetLastError(); +#else + return errno; +#endif + } + + enum + { +#ifdef _WIN32 + ErrorWouldBlock = WSAEWOULDBLOCK +#else + ErrorWouldBlock = EWOULDBLOCK +#endif + }; + + enum + { +#ifdef _WIN32 + ShutdownReceive = SD_RECEIVE, + ShutdownSend = SD_SEND, + ShutdownBoth = SD_BOTH +#else + ShutdownReceive = SHUT_RD, + ShutdownSend = SHUT_WR, + ShutdownBoth = SHUT_RDWR +#endif + }; +}; + +/// +/// Socket Data +/// +struct SocketData +{ + Socket socket; + int flags; + + SocketData() : socket(), flags(0) {} + + bool operator==(Socket s) { return (socket == s); } +}; + +/// +/// Socket Reactor +/// +struct Reactor : protected common::Thread +{ + + /// + /// Socket State callback + /// + class SocketCallback + { + public: + virtual void onSocketReadable(Socket sock) = 0; + virtual void onSocketWritable(Socket sock) = 0; + virtual void onSocketAcceptable(Socket sock) = 0; + virtual void onSocketClosed(Socket sock) = 0; + }; + + /// + /// Socket State + /// + enum State + { + Readable = 1, + Writable = 2, + Acceptable = 4, + Closed = 8 + }; + + SocketCallback &m_callback; + + std::vector m_sockets; + +#ifdef _WIN32 + /* use WinSock events on Windows */ + std::vector m_events{}; +#endif + +#ifdef __linux__ + /* use epoll on Linux */ + int m_epollFd; +#endif + +#ifdef TARGET_OS_MAC + /* use kqueue on Mac */ +# define KQUEUE_SIZE 32 + int kq{0}; + struct kevent m_events[KQUEUE_SIZE]; +#endif + +public: + Reactor(SocketCallback &callback) : m_callback(callback) + { +#ifdef __linux__ +# ifdef ANDROID + m_epollFd = ::epoll_create(0); +# else + m_epollFd = ::epoll_create1(0); +# endif +#endif + +#ifdef TARGET_OS_MAC + bzero(&m_events[0], sizeof(m_events)); + kq = kqueue(); +#endif + } + + ~Reactor() + { +#ifdef __linux__ + ::close(m_epollFd); +#endif +#ifdef TARGET_OS_MAC + ::close(kq); +#endif + } + + /// + /// Add Socket + /// + /// + /// + void addSocket(const Socket &socket, int flags) + { + if (flags == 0) + { + removeSocket(socket); + } + else + { + auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); + if (it == m_sockets.end()) + { + LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", static_cast(socket), flags); +#ifdef _WIN32 + m_events.push_back(::WSACreateEvent()); +#endif +#ifdef __linux__ + epoll_event event = {}; + event.data.fd = socket; + event.events = 0; + ::epoll_ctl(m_epollFd, EPOLL_CTL_ADD, socket, &event); +#endif +#ifdef TARGET_OS_MAC + struct kevent event; + bzero(&event, sizeof(event)); + event.ident = socket.m_sock; + EV_SET(&event, event.ident, EVFILT_READ, EV_ADD, 0, 0, NULL); + kevent(kq, &event, 1, NULL, 0, NULL); + EV_SET(&event, event.ident, EVFILT_WRITE, EV_ADD, 0, 0, NULL); + kevent(kq, &event, 1, NULL, 0, NULL); +#endif + m_sockets.push_back(SocketData()); + m_sockets.back().socket = socket; + m_sockets.back().flags = 0; + it = m_sockets.end() - 1; + } + else + { + LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", static_cast(socket), flags); + } + + if (it->flags != flags) + { + it->flags = flags; +#ifdef _WIN32 + long lNetworkEvents = 0; + if (it->flags & Readable) + { + lNetworkEvents |= FD_READ; + } + if (it->flags & Writable) + { + lNetworkEvents |= FD_WRITE; + } + if (it->flags & Acceptable) + { + lNetworkEvents |= FD_ACCEPT; + } + if (it->flags & Closed) + { + lNetworkEvents |= FD_CLOSE; + } + auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); + ::WSAEventSelect(socket, *eventIt, lNetworkEvents); +#endif +#ifdef __linux__ + int events = 0; + if (it->flags & Readable) + { + events |= EPOLLIN; + } + if (it->flags & Writable) + { + events |= EPOLLOUT; + } + if (it->flags & Acceptable) + { + events |= EPOLLIN; + } + // if (it->flags & Closed) - always handled (EPOLLERR | EPOLLHUP) + epoll_event event = {}; + event.data.fd = socket; + event.events = events; + ::epoll_ctl(m_epollFd, EPOLL_CTL_MOD, socket, &event); +#endif +#ifdef TARGET_OS_MAC + // TODO: [MG] - Mac OS X socket doesn't currently support updating flags +#endif + } + } + } + + /// + /// Remove Socket + /// + /// + void removeSocket(const Socket &socket) + { + LOG_TRACE("Reactor: Removing socket 0x%x", static_cast(socket)); + auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); + if (it != m_sockets.end()) + { +#ifdef _WIN32 + auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); + ::WSAEventSelect(it->socket, *eventIt, 0); + ::WSACloseEvent(*eventIt); + m_events.erase(eventIt); +#endif +#ifdef __linux__ + ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, socket, nullptr); +#endif +#ifdef TARGET_OS_MAC + struct kevent event; + bzero(&event, sizeof(event)); + event.ident = socket; + EV_SET(&event, socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + //// Already removed? + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + EV_SET(&event, socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + //// Already removed? + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } +#endif + m_sockets.erase(it); + } + } + + /// + /// Start server + /// + void start() + { + LOG_INFO("Reactor: Starting..."); + startThread(); + } + + /// + /// Stop server + /// + void stop() + { + LOG_INFO("Reactor: Stopping..."); + joinThread(); +#ifdef _WIN32 + for (auto &hEvent : m_events) + { + ::WSACloseEvent(hEvent); + } +#else /* Linux and Mac */ + for (auto &sd : m_sockets) + { +# ifdef __linux__ + ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, sd.socket, nullptr); +# endif +# ifdef TARGET_OS_MAC + struct kevent event; + bzero(&event, sizeof(event)); + event.ident = sd.socket; + EV_SET(&event, sd.socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + EV_SET(&event, sd.socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } +# endif + } +#endif + m_sockets.clear(); + } + + /// + /// Thread Loop for async events processing + /// + virtual void onThread() override + { + LOG_INFO("Reactor: Thread started"); + while (!shouldTerminate()) + { +#ifdef _WIN32 + DWORD dwResult = ::WSAWaitForMultipleEvents(static_cast(m_events.size()), + m_events.data(), FALSE, 500, FALSE); + if (dwResult == WSA_WAIT_TIMEOUT) + { + continue; + } + + assert(dwResult <= WSA_WAIT_EVENT_0 + m_events.size()); + int index = dwResult - WSA_WAIT_EVENT_0; + Socket socket = m_sockets[index].socket; + int flags = m_sockets[index].flags; + + WSANETWORKEVENTS ne; + ::WSAEnumNetworkEvents(socket, m_events[index], &ne); + LOG_TRACE("Reactor: Handling socket 0x%x (index %d) with active flags 0x%x (armed 0x%x)", + static_cast(socket), index, ne.lNetworkEvents, flags); + + if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) + { + m_callback.onSocketReadable(socket); + } + if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) + { + m_callback.onSocketWritable(socket); + } + if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) + { + m_callback.onSocketAcceptable(socket); + } + if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) + { + m_callback.onSocketClosed(socket); + } +#endif + +#ifdef __linux__ + epoll_event events[4]; + int result = ::epoll_wait(m_epollFd, events, sizeof(events) / sizeof(events[0]), 500); + if (result == 0 || (result == -1 && errno == EINTR)) + { + continue; + } + + assert(result >= 1 && static_cast(result) <= sizeof(events) / sizeof(events[0])); + for (int i = 0; i < result; i++) + { + auto it = std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); + assert(it != m_sockets.end()); + Socket socket = it->socket; + int flags = it->flags; + + LOG_TRACE("Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), events[i].events, flags); + + if ((flags & Readable) && (events[i].events & EPOLLIN)) + { + m_callback.onSocketReadable(socket); + } + if ((flags & Writable) && (events[i].events & EPOLLOUT)) + { + m_callback.onSocketWritable(socket); + } + if ((flags & Acceptable) && (events[i].events & EPOLLIN)) + { + m_callback.onSocketAcceptable(socket); + } + if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) + { + m_callback.onSocketClosed(socket); + } + } +#endif + +#if defined(TARGET_OS_MAC) + unsigned waitms = 500; // never block for more than 500ms + struct timespec timeout; + timeout.tv_sec = waitms / 1000; + timeout.tv_nsec = (waitms % 1000) * 1000 * 1000; + + int nev = kevent(kq, NULL, 0, m_events, KQUEUE_SIZE, &timeout); + for (int i = 0; i < nev; i++) + { + struct kevent &event = m_events[i]; + int fd = (int)event.ident; + auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); + assert(it != m_sockets.end()); + Socket socket = it->socket; + int flags = it->flags; + + LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", static_cast(socket), + event.flags, event.fflags); + + if (event.filter == EVFILT_READ) + { + if (flags & Acceptable) + { + m_callback.onSocketAcceptable(socket); + } + if (flags & Readable) + { + m_callback.onSocketReadable(socket); + } + continue; + } + + if (event.filter == EVFILT_WRITE) + { + if (flags & Writable) + { + m_callback.onSocketWritable(socket); + } + continue; + } + + if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) + { + LOG_TRACE("event.filter=%s", "EVFILT_WRITE"); + m_callback.onSocketClosed(socket); + it->flags = Closed; + struct kevent kevt; + EV_SET(&kevt, event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + EV_SET(&kevt, event.ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { + LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); + } + continue; + } + LOG_ERROR("Reactor: unhandled kevent!"); + } +#endif + } + LOG_TRACE("Reactor: Thread done"); + } +}; + +} // namespace SocketTools From 7e89c878c8f67e3ffe1d84b3c8773a07fffc4803 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 28 Jul 2020 12:35:37 +0000 Subject: [PATCH 02/37] Add index error status/tooltip description, precise timestamps --- .../zpages_static_files/tracez/script.js | 74 +++++++++++++++++-- .../zpages_static_files/tracez/style.css | 19 +++++ 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/ext/src/zpages/zpages_static_files/tracez/script.js b/ext/src/zpages/zpages_static_files/tracez/script.js index c63bc258e4..39ed21f13d 100644 --- a/ext/src/zpages/zpages_static_files/tracez/script.js +++ b/ext/src/zpages/zpages_static_files/tracez/script.js @@ -6,9 +6,48 @@ const latencies = [ '>1s', '>10s', '>100s', ]; +const statusCodeDescriptions = { + 'OK': 'The operation completed successfully.', + 'CANCELLED': 'The operation was cancelled (typically by the caller).', + 'UNKNOWN': `Unknown error. An example of where this error may be returned is if a Status value received + from another address space belongs to an error-space that is not known in this address space. + Also errors raised by APIs that do not return enough error information may be converted to + this error.`, + 'INVALID_ARGUMENT': `Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. + INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the + system (e.g., a malformed file name).`, + 'DEADLINE_EXCEEDED': `Deadline expired before operation could complete. For operations that change the state of the + system, this error may be returned even if the operation has completed successfully. For + example, a successful response from a server could have been delayed long enough for the + deadline to expire.`, + 'NOT_FOUND' : 'Some requested entity (e.g., file or directory) was not found.', + 'ALREADY_EXISTS': 'Some entity that we attempted to create (e.g., file or directory) already exists.', + 'PERMISSION_DENIED': `The caller does not have permission to execute the specified operation. PERMISSION_DENIED + must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED + instead for those errors). PERMISSION_DENIED must not be used if the caller cannot be + identified (use UNAUTHENTICATED instead for those errors).`, + 'RESOURCE_EXHAUSTED': `Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system + is out of space.`, + 'FAILED_PRECONDITION': `Operation was rejected because the system is not in a state required for the operation's + execution. For example, directory to be deleted may be non-empty, an rmdir operation is + applied to a non-directory, etc.`, + 'ABORTED': `The operation was aborted, typically due to a concurrency issue like sequencer check + failures, transaction aborts, etc`, + 'OUT_OF_RANGE': `Operation was attempted past the valid range. E.g., seeking or reading past end of file.`, + 'UNIMPLEMENTED': 'Operation is not implemented or not supported/enabled in this service.', + 'INTERNAL': `Internal errors. Means some invariants expected by underlying system has been broken. If you + see one of these errors, something is very broken.`, + 'UNAVAILABLE': `The service is currently unavailable. This is a most likely a transient condition and may be + corrected by retrying with a backoff.`, + 'DATA_LOSS': 'Unrecoverable data loss or corruption.', + 'UNAUTHENTICATED': 'The request does not have valid authentication credentials for the operation.', +}; + +const details = {'status': statusCodeDescriptions} + // Latency info is returned as an array, so they need to be parsed accordingly -const getLatencyCell = (span, i, h) => `${span[h][i]}`; +const getLatencyCell = (span, i, h) => `${span[h][i]}`; // Pretty print a cell with a map const getKeyValueCell = (span, i, h) => ` @@ -17,7 +56,7 @@ const getKeyValueCell = (span, i, h) => ` // Standard categories when checking span details const idCols = ['spanid', 'parentid', 'traceid'] -const detailCols = ['description']; // Columns error, running, and latency spans all share +const detailCols = []; // Columns error, running, and latency spans all share const dateCols = ['start']; // Categories to change to date const numCols = ['duration']; // Categories to change to num const clickCols = ['error', 'running']; // Non-latency clickable cols @@ -123,17 +162,36 @@ const getArrayCells = (h, span) => span[h].length ? (span[h].map((_, i) => arrayCols[h](span, i, h))).join('') : 'Empty'; -const EmptyContent = () => `(not set)` +const emptyContent = () => `(not set)` + +const dateStr = nanosec => { + const mainDate = new Date(nanosec / 1000000).toLocaleString(); + let lostPrecision = String(nanosec % 1000000); + while (lostPrecision.length < 6) lostPrecision = 0 + lostPrecision; + const endingLocation = mainDate.indexOf('M') - 2; + return `${mainDate.substr(0, endingLocation)}:${lostPrecision}${mainDate.substr(endingLocation)}`; +} + +const detailCell = (h, span) => { + const detailKey = Object.keys(details[h])[span[h]]; + const detailVal = details[h][detailKey]; + return ` + ${detailKey} + ${detailVal} + `; +} // Convert cells to Date strings if needed const getCellContent = (h, span) => { - if (!isDate(h)) return (span[h] !== '') ? span[h] : EmptyContent(); - return new Date(span[h] / 1000000).toJSON(); + if (h in details) return detailCell(h, span); + else if (span[h] === '') return emptyContent(); + else if (!isDate(h)) return span[h]; + return dateStr(span[h]); }; // Create cell based on what header we want to render const getCell = (h, span) => (isArrayCol(h)) ? getArrayCells(h, span) - : `` + `${getCellContent(h, span)}`; @@ -165,7 +223,7 @@ function overwriteTable(group, url_end = '') { function updateSubheading(group, name) { if (hasSubheading(group)) { document.getElementById(getHTML(isLatency(group) ? 'latency' : group) + '_header') - .innerHTML = `

${name}
+ .innerHTML = `

${name}
${(isLatency(group) ? `${latencies[group]} Bucket` : toTitlecase(group))} Spans

Showing sampled span details (up to 5). ${getStatusHTML(group)}

`; diff --git a/ext/src/zpages/zpages_static_files/tracez/style.css b/ext/src/zpages/zpages_static_files/tracez/style.css index cbb92a9173..64f3fb7633 100644 --- a/ext/src/zpages/zpages_static_files/tracez/style.css +++ b/ext/src/zpages/zpages_static_files/tracez/style.css @@ -109,3 +109,22 @@ img { width: 50%; max-width: 500px; } + +.has-tooltip:hover .tooltip { + display: block; +} + +.tooltip { + display: none; + position: absolute; +} + +.tooltip, .tooltip:hover{ + background: #ffffffd9; + padding: 10px; + z-index: 1000; + color: #252525 !important; + border-radius: 10px; + margin: 3px 20px 0 0; +} + From 6fe0d38820e41e129b4276e6efc650516a7d7d96 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 28 Jul 2020 12:52:51 +0000 Subject: [PATCH 03/37] Move refresh + time to top right --- ext/src/zpages/zpages_static_files/tracez/index.html | 4 ++-- ext/src/zpages/zpages_static_files/tracez/style.css | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ext/src/zpages/zpages_static_files/tracez/index.html b/ext/src/zpages/zpages_static_files/tracez/index.html index 6fd6ae0644..7f9820a686 100644 --- a/ext/src/zpages/zpages_static_files/tracez/index.html +++ b/ext/src/zpages/zpages_static_files/tracez/index.html @@ -8,8 +8,8 @@

zPages TraceZ

-

Last Updated:

- + Last Updated:
+


diff --git a/ext/src/zpages/zpages_static_files/tracez/style.css b/ext/src/zpages/zpages_static_files/tracez/style.css index 64f3fb7633..9ec75dcfca 100644 --- a/ext/src/zpages/zpages_static_files/tracez/style.css +++ b/ext/src/zpages/zpages_static_files/tracez/style.css @@ -36,15 +36,18 @@ td, th { } #top-right { + text-align: right; position: absolute; top: 10px; - right: 10px + right: 10px; + text-shadow: .5px .5px .25px #fff; } #top-right button { color: #f6a81c; border: 2px solid #f6a81c; - padding: 8px; + padding: 10px; + margin: 10px; text-transform: uppercase; letter-spacing: 1px; background-color: white; @@ -119,7 +122,7 @@ img { position: absolute; } -.tooltip, .tooltip:hover{ +.tooltip, .tooltip:hover { background: #ffffffd9; padding: 10px; z-index: 1000; From f315a19ed7ecbb1ad9e9ce29f57aca3ade941a17 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 28 Jul 2020 12:57:03 +0000 Subject: [PATCH 04/37] Change html double quotes to single quotes --- .../zpages_static_files/tracez/index.html | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ext/src/zpages/zpages_static_files/tracez/index.html b/ext/src/zpages/zpages_static_files/tracez/index.html index 7f9820a686..061c05e920 100644 --- a/ext/src/zpages/zpages_static_files/tracez/index.html +++ b/ext/src/zpages/zpages_static_files/tracez/index.html @@ -2,22 +2,22 @@ zPages TraceZ - - + + - +

zPages TraceZ

- Last Updated:
-
+ Last Updated:
+


-
-
+
+
- - - - + + + + @@ -26,14 +26,14 @@

zPages TraceZ

Span Name Latency Samples
- +


- -
- + +
+
From beac08a18b40152554a8433b03c33551107638a1 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 28 Jul 2020 14:16:15 +0000 Subject: [PATCH 05/37] Add working emitted HTML file --- .../ext/zpages/tracez_http_server.h | 94 +++++++++++++++---- .../ext/zpages/zpages_http_server.h | 3 +- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h index 74f3c5b491..350955c70c 100644 --- a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h @@ -11,6 +11,9 @@ #include "opentelemetry/ext/zpages/zpages_http_server.h" #include "nlohmann/json.hpp" +#define HAVE_HTTP_DEBUG +#define HAVE_CONSOLE_LOG + using json = nlohmann::json; OPENTELEMETRY_BEGIN_NAMESPACE @@ -28,7 +31,7 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { */ TracezHttpServer(std::unique_ptr &&aggregator, std::string host = "localhost", int port = 30000) : - opentelemetry::ext::zpages::zPagesHttpServer("/tracez/get", host, port), + opentelemetry::ext::zpages::zPagesHttpServer("/tracez", host, port), data_aggregator_(std::move(aggregator)) { InitializeTracezEndpoint(*this); InitializeFileEndpoint(*this); @@ -88,28 +91,81 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { */ HTTP_SERVER_NS::HttpRequestCallback Serve{[&](HTTP_SERVER_NS::HttpRequest const& req, HTTP_SERVER_NS::HttpResponse& resp) { - resp.headers[testing::CONTENT_TYPE] = "application/json"; - - std::string query = GetQuery(req.uri); - - if (StartsWith(query, "latency")) { - auto queried_latency_name = GetAfterSlash(query); - auto queried_latency_index = std::stoi(GetBeforeSlash(queried_latency_name)); - auto queried_name = GetAfterSlash(queried_latency_name); - resp.body = GetLatencySpansJSON(queried_name, queried_latency_index).dump(); + std::string query = GetQuery(req.uri); // tracez + + if (StartsWith(query, "get")) { + resp.headers[testing::CONTENT_TYPE] = "application/json"; + query = GetAfterSlash(query); + if (StartsWith(query, "latency")) { + auto queried_latency_name = GetAfterSlash(query); + auto queried_latency_index = std::stoi(GetBeforeSlash(queried_latency_name)); + auto queried_name = GetAfterSlash(queried_latency_name); + resp.body = GetLatencySpansJSON(queried_name, queried_latency_index).dump(); + } + else { + auto queried_name = GetAfterSlash(query); + if (StartsWith(query, "aggregations")) { + resp.body = GetAggregations().dump(); + } + else if (StartsWith(query, "running")) { + resp.body = GetRunningSpansJSON(queried_name).dump(); + } + else if (StartsWith(query, "error")) { + resp.body = GetErrorSpansJSON(queried_name).dump(); + } + else resp.body = json::array(); + } } else { - auto queried_name = GetAfterSlash(query); - if (StartsWith(query, "aggregations")) { - resp.body = GetAggregations().dump(); - } - else if (StartsWith(query, "running")) { - resp.body = GetRunningSpansJSON(queried_name).dump(); + //resp.body = StartsWith(query, "index.html") ? "cool" : " no "; + + + if (StartsWith(query, "index.html")) { + resp.headers[testing::CONTENT_TYPE] = "text/html"; + resp.body = "" + "" + " " + " zPages TraceZ" + " " + " " + " " + " " + " " + "

zPages TraceZ

" + " Last Updated:
" + "
" + "

" + "
" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "
Span NameError SamplesRunningLatency Samples
" + " " + "
" + "
" + "
" + "
" + " " + "
" + " " + "
" + "
" + " " + ""; } - else if (StartsWith(query, "error")) { - resp.body = GetErrorSpansJSON(queried_name).dump(); + else { resp.headers[testing::CONTENT_TYPE] = "application/json"; + resp.body = "[]"; } - else resp.body = json::array(); } return 200; diff --git a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h index ca0ec06928..5e94e924f3 100644 --- a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h @@ -8,7 +8,8 @@ #include #include "opentelemetry/ext/http/server/HttpServer.h" - +#define HAVE_HTTP_DEBUG +#define HAVE_CONSOLE_LOG OPENTELEMETRY_BEGIN_NAMESPACE namespace ext { namespace zpages { From e297076215f9adb2d2cdf80125f7b93c2684fad6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 28 Jul 2020 16:23:04 +0000 Subject: [PATCH 06/37] Remove handler --- .../opentelemetry/ext/zpages/tracez_handler.h | 208 ------------------ 1 file changed, 208 deletions(-) delete mode 100644 ext/include/opentelemetry/ext/zpages/tracez_handler.h diff --git a/ext/include/opentelemetry/ext/zpages/tracez_handler.h b/ext/include/opentelemetry/ext/zpages/tracez_handler.h deleted file mode 100644 index a0cededd33..0000000000 --- a/ext/include/opentelemetry/ext/zpages/tracez_handler.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nlohmann/json.hpp" -#include "opentelemetry/ext/zpages/zpages_http_server.h" -#include "opentelemetry/ext/zpages/tracez_data_aggregator.h" - -using json = nlohmann::json; -using namespace opentelemetry::sdk::trace; -using namespace opentelemetry::ext::zpages; - -namespace ext -{ -namespace zpages -{ - -/** Convinient data structure to convert status code enum to string **/ -const std::arraystatusCodesDescriptions = { - "OK", - "CANCELLED", - "UNKNOWN", - "INVALID_ARGUMENT", - "DEADLINE_EXCEEDED", - "NOT_FOUND", - "ALREADY_EXISTS", - "PERMISSION_DENIED", - "RESOURCE_EXHAUSTED", - "FAILED_PRECONDITION", - "ABORTED", - "OUT_OF_RANGE", - "UNIMPLEMENTED", - "INTERNAL", - "UNAVAILABLE", - "DATA_LOSS", - "UNAUTHENTICATED" -}; - -class TracezHandler { - public: - json LatencySampleSpansJSON(const std::string& name, int latency_bucket){ - auto temp = json::array(); - - if(aggregated_data_.find(name) != aggregated_data_.end()){ - const auto &latency_samples = aggregated_data_[name].sample_latency_spans[latency_bucket]; - for(const auto &latency_sample : latency_samples){ - temp.push_back({ - {"spanid", latency_sample.span_id}, - {"parentid", latency_sample.parent_id}, - {"traceid", latency_sample.trace_id}, - {"description", latency_sample.description}, - {"start", latency_sample.start_time}, - {"duration", latency_sample.duration}, - }); - } - } - - return temp; - } - - void updateAggregations() { - aggregated_data_ = data_aggregator_->GetAggregatedTracezData(); - } - - json GetErrorSampleSpanJSON(const std::string& name){ - auto temp = json::array(); - - if(aggregated_data_.find(name) != aggregated_data_.end()){ - const auto &error_samples = aggregated_data_[name].sample_error_spans; - for(const auto &error_sample : error_samples){ - temp.push_back({ - {"spanid", error_sample.span_id}, - {"parentid", error_sample.parent_id}, - {"traceid", error_sample.trace_id}, - {"description", error_sample.description}, - {"start", error_sample.start_time}, - {"status",statusCodesDescriptions[error_sample.status_code]}, - }); - } - } - return temp; - } - - json GetRunningSampleSpanJSON(const std::string& name) { - auto temp = json::array(); - if(aggregated_data_.find(name) != aggregated_data_.end()){ - const auto &running_samples = aggregated_data_[name].sample_running_spans; - for(const auto &running_sample : running_samples){ - temp.push_back({ - {"spanid", running_sample.span_id}, - {"parentid", running_sample.parent_id}, - {"traceid", running_sample.trace_id}, - {"description", running_sample.description}, - {"start", running_sample.start_time}, - }); - } - } - return temp; - } - - json GetAggregationSummary() { - updateAggregations(); - auto temp = json::array(); - for(const auto &aggregation_group: aggregated_data_){ - const auto &buckets = aggregation_group.second; - const auto &complete_ok_counts = buckets.completed_span_count_per_latency_bucket; - auto latency = json::array(); - for (int i = 0; i < 9; i++) { - latency.push_back(complete_ok_counts[i]); - } - temp.push_back({ - {"name", aggregation_group.first}, - {"error", buckets.error_span_count}, - {"running", buckets.running_span_count}, - {"latency", latency} - }); - } - return temp; - } - - TracezHandler(std::unique_ptr &&aggregator) { - data_aggregator_ = std::move(aggregator); - }; - - // Return query after endpoint - std::string GetSuffix(const std::string& uri) { - if (endpoint_.length() + 1 > uri.length()) return uri; - return uri.substr(endpoint_.length() + 1); - } - - // Returns whether str starts with pre - bool StartsWith(const std::string& str, std::string pre) { - if (pre.length() > str.length()) return false; - return str.substr(0, pre.length()) == pre; - } - - // Check if str starts with endpoint - bool StartsWith(const std::string& str) { - return StartsWith(str, endpoint_); - } - - // Returns string after leftmost backslash. Used for getting bucket number - // primarily in latency - std::string GetAfterSlash(const std::string& str) { - const auto& backslash = str.find("/"); - if (backslash == std::string::npos || backslash == str.length()) return ""; - return str.substr(backslash + 1); - } - - // Returns string before leftmost backslash. Used for getting aggregation group - // name - std::string GetBeforeSlash(const std::string& str) { - const auto& backslash = str.find("/"); - if (backslash == std::string::npos || backslash == str.length()) return str; - return str.substr(0, backslash); - } - - HTTP_SERVER_NS::HttpRequestCallback Serve{[&](HTTP_SERVER_NS::HttpRequest const& req, - HTTP_SERVER_NS::HttpResponse& resp) { - resp.headers[testing::CONTENT_TYPE] = "application/json"; - if (StartsWith(req.uri)) { - std::string query = GetSuffix(req.uri); - if (StartsWith(query, "latency")) { - auto queried_bucket_name = GetAfterSlash(query); - auto queried_latency_index = std::stoi(GetBeforeSlash(queried_bucket_name)); - auto queried_name = GetAfterSlash(queried_bucket_name); - resp.body = LatencySampleSpansJSON(queried_name, queried_latency_index).dump(); - } - else { - auto queried_name = GetAfterSlash(query); - - if (StartsWith(query, "aggregations")) { - resp.body = GetAggregationSummary().dump(); - } - else if (StartsWith(query, "running")) { - resp.body = GetRunningSampleSpanJSON(queried_name).dump(); - } - else if (StartsWith(query, "error")) { - resp.body = GetErrorSampleSpanJSON(queried_name).dump(); - } - } - } - else { - resp.body = GetAggregationSummary().dump(); - }; - return 200; - }}; - - std::string GetEndpoint() { - return endpoint_; - } - - private: - const std::string endpoint_ = "/tracez/get"; - std::map aggregated_data_; - std::unique_ptr data_aggregator_; - -}; - -} // namespace zpages -} // namespace ext From 0390b2a266233441fcf01c9856f8c12938877620 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 28 Jul 2020 18:59:31 +0000 Subject: [PATCH 07/37] Replace static files with emitted c++ --- .../ext/zpages/static/tracez_index.h | 42 +++ .../ext/zpages/static/tracez_script.h | 256 +++++++++++++++++ .../ext/zpages/static/tracez_style.h | 148 ++++++++++ .../ext/zpages/tracez_http_server.h | 60 +--- .../images/opentelemetry.png | Bin 29271 -> 0 bytes .../zpages_static_files/tracez/index.html | 40 --- .../zpages_static_files/tracez/script.js | 258 ------------------ .../zpages_static_files/tracez/style.css | 133 --------- 8 files changed, 461 insertions(+), 476 deletions(-) create mode 100644 ext/include/opentelemetry/ext/zpages/static/tracez_index.h create mode 100644 ext/include/opentelemetry/ext/zpages/static/tracez_script.h create mode 100644 ext/include/opentelemetry/ext/zpages/static/tracez_style.h delete mode 100644 ext/src/zpages/zpages_static_files/images/opentelemetry.png delete mode 100644 ext/src/zpages/zpages_static_files/tracez/index.html delete mode 100644 ext/src/zpages/zpages_static_files/tracez/script.js delete mode 100644 ext/src/zpages/zpages_static_files/tracez/style.css diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_index.h b/ext/include/opentelemetry/ext/zpages/static/tracez_index.h new file mode 100644 index 0000000000..d0e8e78779 --- /dev/null +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_index.h @@ -0,0 +1,42 @@ +#pragma once + +const char tracez_index[] = "" + "" + " " + " zPages TraceZ" + " " + " " + " " + " " + " " + "

zPages TraceZ

" + " Last Updated:
" + "
" + "

" + "
" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "
Span NameError SamplesRunningLatency Samples
" + " " + "
" + "
" + "
" + "
" + " " + "
" + " " + "
" + "
" + " " + ""; diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_script.h b/ext/include/opentelemetry/ext/zpages/static/tracez_script.h new file mode 100644 index 0000000000..730713aff5 --- /dev/null +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_script.h @@ -0,0 +1,256 @@ +#pragma once + +const char tracez_script[] = "window.onload = () => refreshData();" +"const latencies = [" +" '>0s', '>10µs', '>100µs'," +" '>1ms', '>10ms', '>100ms'," +" '>1s', '>10s', '>100s'," +"];" +"" +"const statusCodeDescriptions = {" +" 'OK': 'The operation completed successfully.'," +" 'CANCELLED': 'The operation was cancelled (typically by the caller).'," +" 'UNKNOWN': `Unknown error. An example of where this error may be returned is if a Status value received" +" from another address space belongs to an error-space that is not known in this address space." +" Also errors raised by APIs that do not return enough error information may be converted to" +" this error.`," +" 'INVALID_ARGUMENT': `Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION." +" INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the" +" system (e.g., a malformed file name).`," +" 'DEADLINE_EXCEEDED': `Deadline expired before operation could complete. For operations that change the state of the" +" system, this error may be returned even if the operation has completed successfully. For" +" example, a successful response from a server could have been delayed long enough for the" +" deadline to expire.`," +" 'NOT_FOUND' : 'Some requested entity (e.g., file or directory) was not found.'," +" 'ALREADY_EXISTS': 'Some entity that we attempted to create (e.g., file or directory) already exists.'," +" 'PERMISSION_DENIED': `The caller does not have permission to execute the specified operation. PERMISSION_DENIED" +" must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED" +" instead for those errors). PERMISSION_DENIED must not be used if the caller cannot be" +" identified (use UNAUTHENTICATED instead for those errors).`," +" 'RESOURCE_EXHAUSTED': `Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system" +" is out of space.`," +" 'FAILED_PRECONDITION': `Operation was rejected because the system is not in a state required for the operation's" +" execution. For example, directory to be deleted may be non-empty, an rmdir operation is" +" applied to a non-directory, etc.`," +" 'ABORTED': `The operation was aborted, typically due to a concurrency issue like sequencer check" +" failures, transaction aborts, etc`," +" 'OUT_OF_RANGE': `Operation was attempted past the valid range. E.g., seeking or reading past end of file.`," +" 'UNIMPLEMENTED': 'Operation is not implemented or not supported/enabled in this service.'," +" 'INTERNAL': `Internal errors. Means some invariants expected by underlying system has been broken. If you" +" see one of these errors, something is very broken.`," +" 'UNAVAILABLE': `The service is currently unavailable. This is a most likely a transient condition and may be" +" corrected by retrying with a backoff.`," +" 'DATA_LOSS': 'Unrecoverable data loss or corruption.'," +" 'UNAUTHENTICATED': 'The request does not have valid authentication credentials for the operation.'," +"};" +"" +"const details = {'status': statusCodeDescriptions};" +"" +"/* Latency info is returned as an array, so they need to be parsed accordingly */" +"const getLatencyCell = (span, i, h) => `${span[h][i]}`;" +"" +"/* Pretty print a cell with a map */" +"const getKeyValueCell = (span, i, h) => `" +" ${JSON.stringify(span[h][i], null, 2)}" +" `;" +"" +"/* Standard categories when checking span details */" +"const idCols = ['spanid', 'parentid', 'traceid'];" +"const detailCols = []; /* Columns error, running, and latency spans all share */" +"const dateCols = ['start']; /* Categories to change to date */" +"const numCols = ['duration']; /* Categories to change to num */" +"const clickCols = ['error', 'running']; /* Non-latency clickable cols */" +"const arrayCols = { " +" 'latency': getLatencyCell," +" 'events': getKeyValueCell," +" 'attributes': getKeyValueCell" +"};" +"" +"const base_endpt = '/tracez/get/'; /* For making GET requests */" +"/* Maps table types to their approporiate formatting */" +"const tableFormatting = {" +" 'all': {" +" 'url': base_endpt + 'aggregations'," +" 'html_id': 'overview_table'," +" 'sizing': [" +" {'sz': 'md', 'repeats': 1}," +" {'sz': 'sm', 'repeats': 11}," +" ]," +" 'headings': ['name', ...clickCols, 'latency']," +" 'cell_headings': ['name', ...clickCols, ...latencies]," +" }," +" 'error': {" +" 'url': base_endpt + 'error/'," +" 'html_id': 'name_type_detail_table'," +" 'sizing': [" +" {'sz': 'sm', 'repeats': 5}," +" {'sz': 'md', 'repeats': 1}," +" ]," +" 'headings': [...idCols, ...dateCols, 'status', ...detailCols]," +" 'has_subheading': true," +" }," +" 'running': {" +" 'url': base_endpt + 'running/'," +" 'html_id': 'name_type_detail_table'," +" 'sizing': [" +" {'sz': 'sm', 'repeats': 4}," +" {'sz': 'md', 'repeats': 1}," +" ]," +" 'headings': [...idCols, ...dateCols, ...detailCols]," +" 'has_subheading': true," +" 'status': 'pending'," +" }," +" 'latency': {" +" 'url': base_endpt + 'latency/'," +" 'html_id': 'name_type_detail_table'," +" 'sizing': [" +" {'sz': 'sm', 'repeats': 5}," +" {'sz': 'md', 'repeats': 1}," +" ]," +" 'headings': [...idCols, ...dateCols, ...numCols, ...detailCols]," +" 'has_subheading': true," +" 'status': 'ok'" +" }" +"};" +"const getFormat = group => tableFormatting[group];" +"" +"" +"/* Getters using formatting config variable */" +"const getURL = group => getFormat(group)['url'];" +"const getHeadings = group => getFormat(group)['headings'];" +"const getCellHeadings = group => 'cell_headings' in getFormat(group)" +" ? getFormat(group)['cell_headings'] : getHeadings(group); " +"const getSizing = group => getFormat(group)['sizing'];" +"const getStatus = group => isLatency(group) ? 'ok' : getFormat(group)['status'];" +"const getHTML = group => getFormat(group)['html_id'];" +"" +"const isDate = col => new Set(dateCols).has(col);" +"const isLatency = group => !(new Set(clickCols).has(group)); /* non latency clickable cols, change to include latency? */" +"const isArrayCol = group => (new Set(Object.keys(arrayCols)).has(group));" +"const hasCallback = col => new Set(clickCols).has(col); /* Non-latency cb columns */" +"const hideHeader = h => new Set([...clickCols, 'name']).has(h); /* Headers to not show render twice */" +"const hasSubheading = group => isLatency(group) || 'has_subheading' in getFormat(group); " +"const hasStatus = group => isLatency(group) || 'status' in getFormat(group);" +"" +"const toTitlecase = word => word.charAt(0).toUpperCase() + word.slice(1);" +"const updateLastRefreshStr = () => document.getElementById('lastUpdateTime').innerHTML = new Date().toLocaleString();" +"" +"const getStatusHTML = group => !hasStatus(group) ? ''" +" : `All of these spans have status code ${getStatus(group)}`;" +"" +"/* Returns an HTML string that handlles width formatting" +" for a table group */" +"const tableSizing = group => ''" +" + getSizing(group).map(sz =>" +" (``).repeat(sz['repeats']))" +" .join('')" +" + '';" +"" +"/* Returns an HTML string for a table group's headings," +" hiding headings where needed */" +"const tableHeadings = group => ''" +" + getCellHeadings(group).map(h => `${(hideHeader(h) ? '' : h)}`).join('')" +" + '';" +"" +"/* Returns an HTML string, which represents the formatting for" +" the entire header for a table group. This doesn't change, and" +" includes the width formatting and the actual table headers */" +"const tableHeader = group => tableSizing(group) + tableHeadings(group);" +"" +"/* Return formatting for an array-based value based on its header */" +"const getArrayCells = (h, span) => span[h].length" +" ? (span[h].map((_, i) => arrayCols[h](span, i, h))).join('')" +" : 'Empty';" +"" +"const emptyContent = () => `(not set)`;" +"" +"const dateStr = nanosec => {" +" const mainDate = new Date(nanosec / 1000000).toLocaleString();" +" let lostPrecision = String(nanosec % 1000000);" +" while (lostPrecision.length < 6) lostPrecision = 0 + lostPrecision;" +" const endingLocation = mainDate.indexOf('M') - 2;" +" return `${mainDate.substr(0, endingLocation)}:${lostPrecision}${mainDate.substr(endingLocation)}`;" +"};" +"" +"const detailCell = (h, span) => {" +" const detailKey = Object.keys(details[h])[span[h]];" +" const detailVal = details[h][detailKey];" +" return `" +" ${detailKey}" +" ${detailVal}" +" `;" +"};" +"/* Convert cells to Date strings if needed */" +"const getCellContent = (h, span) => {" +" if (h in details) return detailCell(h, span);" +" else if (span[h] === '') return emptyContent();" +" else if (!isDate(h)) return span[h];" +" return dateStr(span[h]);" +"};" +"/* Create cell based on what header we want to render */" +"const getCell = (h, span) => (isArrayCol(h)) ? getArrayCells(h, span)" +" : `` + `${getCellContent(h, span)}`;" +"" +"/* Returns an HTML string with for a span's aggregated data" +" while columns are ordered according to its table group */" +"const tableRow = (group, span) => ''" +" + getHeadings(group).map(h => getCell(h, span)).join('')" +" + '';" +"" +"/* Returns an HTML string from all the data given as" +" table rows, with each row being a group of spans by name */" +"const tableRows = (group, data) => data.map(span => tableRow(group, span)).join('');" +"" +"/* Overwrite a table on the DOM based on the group given by adding" +" its headers and fetching data for its url */" +"function overwriteTable(group, url_end = '') {" +" console.log(getURL(group) + url_end);" +" fetch(getURL(group) + url_end).then(res => res.json())" +" .then(data => {" +" console.log(data);" +" document.getElementById(getHTML(group))" +" .innerHTML = tableHeader(group)" +" + tableRows(group, data);" +" })" +" .catch(err => console.log(err));" +"};" +"" +"/* Adds a title subheading where needed */" +"function updateSubheading(group, name) {" +" if (hasSubheading(group)) {" +" document.getElementById(getHTML(isLatency(group) ? 'latency' : group) + '_header')" +" .innerHTML = `

${name}
" +" ${(isLatency(group) ? `${latencies[group]} Bucket` : toTitlecase(group))}" +" Spans

Showing sampled span details (up to 5)." +" ${getStatusHTML(group)}

`;" +" }" +"};" +"" +"/* Overwrites a table on the DOM based on the group and also" +" changes the subheader, since this a looking at sampled spans */" +"function overwriteDetailedTable(group, name) {" +" if (isLatency(group)) overwriteTable('latency', group + '/' + name);" +" else overwriteTable(group, name);" +" updateSubheading(group, name);" +"};" +"" +"/* Append to a table on the DOM based on the group given */" +"function addToTable(group, url_end = '') {" +" fetch(getURL(group) + url_end).then(res => res.json())" +" .then(data => {" +" const rowsStr = tableRows(group, data);" +" if (!rowsStr) console.log(`No rows added for ${group} table`);" +" document.getElementById(getHTML(group))" +" .getElementsByTagName('tbody')[0]" +" .innerHTML += rowsStr;" +" })" +" .catch(err => console.log(err));" +"};" +"" +"const refreshData = () => {" +" updateLastRefreshStr();" +" overwriteTable('all');" +"};"; diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_style.h b/ext/include/opentelemetry/ext/zpages/static/tracez_style.h new file mode 100644 index 0000000000..e80e7556a0 --- /dev/null +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_style.h @@ -0,0 +1,148 @@ +#pragma once + +const char tracez_style[] = "body {" +" color: #252525;" +" text-align: center;" +" font-family: monospace, sans-serif;" +" word-break: break-all;" +" font-size: .9em" +"}" +"" +"h1 {" +" margin: 0;" +"}" +"" +"table {" +" font-family: monospace, sans-serif;" +" border-collapse: collapse;" +" font-size: 1.05em;" +" width: 100%;" +"}" +"" +".table-wrap {" +" width: 100%;" +" min-width: 700px;" +" max-width: 2000px;" +" margin: auto;" +"}" +"" +"td, th {" +" word-break: break-word;" +" border: 1px solid #f5f5f5;" +" padding: 6px;" +" text-align: center;" +"}" +"" +"#overview_table th, #overview_table tr {" +" border-top: none;" +"}" +"" +"#headers th, #headers tr {" +" border-bottom: none;" +"}" +"" +"#top-right {" +" text-align: right;" +" position: absolute;" +" top: 10px;" +" right: 10px;" +" text-shadow: .5px .5px .25px #fff;" +"}" +"" +"#top-right button {" +" color: #f6a81c;" +" border: 2px solid #f6a81c;" +" padding: 10px;" +" margin: 10px;" +" text-transform: uppercase;" +" letter-spacing: 1px;" +" background-color: white;" +" border-radius: 10px;" +" font-weight: bold;" +"}" +"" +":hover {" +" transition-duration: .15s;" +"}" +"" +"#top-right button:hover {" +" border-color: #4b5fab;" +" color: #4b5fab;" +" cursor: pointer;" +"}" +"" +"tr:nth-child(even) {" +" background-color: #eee;" +"}" +"" +".click {" +" text-decoration: underline dotted #4b5fab;" +"}" +"" +"tr:hover, td:hover, .click:hover {" +" color: white;" +" background-color: #4b5fab;" +"}" +"" +"tr:hover {" +" background-color: #4b5fabcb;" +"}" +"" +"th {" +" background-color: white;" +" color: #252525;" +"}" +"" +".click:hover {" +" cursor: pointer;" +" color: #f6a81ccc;" +"}" +"" +".empty {" +" color: #999;" +"}" +"" +".sm {" +" width: 7%;" +"}" +"" +".md {" +" width: 23%;" +"}" +"" +".lg {" +" width: 63%;" +"}" +"" +"img {" +" width: 50%;" +" max-width: 500px;" +"}" +"" +".subhead-name {" +" color: #4b5fab;" +" text-decoration: underline;" +"}" +"" +".has-tooltip {" +" text-decoration: underline dotted #f6a81c;" +"}" +"" +".has-tooltip:hover .tooltip {" +" display: block;" +"}" +"" +".tooltip {" +" display: none;" +" position: absolute;" +"}" +"" +".tooltip, .tooltip:hover {" +" background: #ffffffd9;" +" padding: 10px;" +" z-index: 1000;" +" color: #252525 !important;" +" border-radius: 10px;" +" margin: 3px 20px 0 0;" +"}" +""; diff --git a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h index 350955c70c..d52e25dd9f 100644 --- a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h @@ -9,6 +9,9 @@ #include "opentelemetry/ext/zpages/tracez_data_aggregator.h" #include "opentelemetry/ext/zpages/zpages_http_server.h" +#include "opentelemetry/ext/zpages/static/tracez_index.h" +#include "opentelemetry/ext/zpages/static/tracez_style.h" +#include "opentelemetry/ext/zpages/static/tracez_script.h" #include "nlohmann/json.hpp" #define HAVE_HTTP_DEBUG @@ -118,53 +121,20 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { } else { //resp.body = StartsWith(query, "index.html") ? "cool" : " no "; - - - if (StartsWith(query, "index.html")) { + if (StartsWith(query, "script.js")) { + resp.headers[testing::CONTENT_TYPE] = "text/javascript"; + resp.body = tracez_script; + } + else if (StartsWith(query, "style.css")) { + resp.headers[testing::CONTENT_TYPE] = "text/css"; + resp.body = tracez_style; + } + else if (query == "/tracez" || query.empty() || StartsWith(query, "index.html")) { resp.headers[testing::CONTENT_TYPE] = "text/html"; - resp.body = "" - "" - " " - " zPages TraceZ" - " " - " " - " " - " " - " " - "

zPages TraceZ

" - " Last Updated:
" - "
" - "

" - "
" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - "
Span NameError SamplesRunningLatency Samples
" - " " - "
" - "
" - "
" - "
" - " " - "
" - " " - "
" - "
" - " " - ""; + resp.body = tracez_index; } - else { resp.headers[testing::CONTENT_TYPE] = "application/json"; - resp.body = "[]"; + else { resp.headers[testing::CONTENT_TYPE] = "text/plain"; + resp.body = query; } } diff --git a/ext/src/zpages/zpages_static_files/images/opentelemetry.png b/ext/src/zpages/zpages_static_files/images/opentelemetry.png deleted file mode 100644 index ac6f4bd7e2f2c4543d5782fd6deee848b12393f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29271 zcmY&A2RN1O`v+x}?3BG{k;;+1vO{*+B>UKV@4X|+EG1->gKU}ELXN#hGLF5+|2g>T z_jg@gpXYh+=U&gf-`5xRR8blammC)Yf#Au?JXV1~u;35~Ivg7l>;#yjCxids*vdS2 zfIx0Cq5h%CsxYoYAhZzK$6{)(sVn13))d2j_0x;A6a{m95W2-HgQ@l1>ApM=w7XrY znTf>DywEvV%-m%~MaLj}cQa@=ap)z;Vl{Ovo_1$RbR0^2eU`tscm#>^Ab+r`q8=wX zSTy0$V{K!D0Vtz>J}f9jV_*CVVIzX0UHmH3mqB$CBGci??@B0c=B?L?=TQUq)7)5O z4z#Us@${NrKL>ouZfS-gioVeQ-4NT5Qv4Av9c6xnWL*e>FjT~&6~P0&}FiCqP9G@<*zh-usqm>i|;5&vh0_hDnaO{1;;9b@n>xB?88iE>8oIkSy z&x$3smZsc@-%4QDtxVaRj68W!>*9IxlN+T)2(7d~6teOI#VVq5%|dNg!h2kxR@f=^ zoW&nenRpO^dl@%wNMMuE1)iku?u7u#UtZv$&Wb9Y&Y7W!mJ@{zN0o0a8O%IA*Gnw1 z7zKnsL8eoWp!5PuIKV3f5byoBsA?0n-ZtrFr~ zRS!^I4{U$2>z{M3r21}f1?$+{M_8991W+h2npQl*E|jqn35f0yl+Z9;a8*nU*c_uX zDSCXtcBTVZ-ytkP&|f_7WdmH(b9*pc;!6V@h;~}bUqYi!{~|6a7r$5=EMI{^@|aC* z5--`&0PLvAcdi9qt_K0XYOt_&p`}FV~tNv zdw5AM5s)X5?(F_gd#?cbaC#F{$qR9&lmYo>f|3%(3-ar&Q8K|zyoSFv9} zi_QaPzS5a!%3d&&GgLA6p|}ITvE{} zbM7dUkx7Em{4d9~GMlY5EyY&D2z?mUTmp61DI5Onpe~X=!-QB@280QGChQp4E zT|9-#G|z?KL<#@&8pFlK-e&+f^LnDMQ~ie&7*cGWymWB%rEu4Q zDSh~p#URmoxzPlqWi&_bA2J87xBYzg;!>gpltj!Azh1hu===2Xi3xrvgwax%N+*cm z1|^;IRO7_P&QSDu7?BAf1bEj52#us8FYG`j66`SA0O&vhJwBC{(6|fR54$H$;Y*qN zNNy$eza12h69Css>}g~)iNK{5Gu9`}LW~(OTgszv2^b&Rp)ALj`Zl;~sL`|Isn9PH zQWxgFEd!Lz@g6F4sRVbF5~!3@s4sOO1n~ce&r!g?l$Z*5*N@l#vj#cp$J_r|gV^yS z{eRZrJgfh|bu`cziNrwmW$Y3S0jdh8x9G>X@YYNQf8dRTrAvMnR@RG#^2V@{ZP5$G z4BZE7qyJgcgZ2CWSrdWv%>S&>!J0kv?|Cy>5Io5LiK_+J%L)I-9v)y%P5Li;^_YOY zJjTE587Khuei8j;uNV`c&-+L2SsVx!JC9-Rm)@Q)+KUNMPVv4}rV^k=`|tERHi)~g z|1sz43*xrRzxB6}^Em#Onk{OLPw;nL3__8w^gsAez^v;(U1z$Bf#<*eJ!0>95Z+4WuX3J}0`|53v7?5{!LR=ZJ&@Mm z+P`%(ik$qvwIpgC@o(J>Ov#|*-&zu^GeMB}kG&b-eZ7SL*i#1V{f_;|-YrxeMWq1Y z=b_9H!Kb5~I1sQldG+(zKEEzNCI=RQ++ z#uI4!WuJ}DKH{&jd~~?NM|V$C^u@7F=>prV?pLy{{{E-iuOJ8a z%3UA+MD=*2h}$Y7@n)IiUo&_PBpDjA^_&P?aiKzfH)+}h=MSIt#r?AdW9eQ@1DKtf zGjX#1nl19=1@v}Wf+PH&Hl72=de&j<>3vK5n^}e8Znkg;fnL(Xs}+A0Kuh6cp96WO z-oq`>L^w?b_})^vp>;iihG>Z7&jwUj<~#_-3IdZ&WF$b9J!VQ5UWF=_);|Oqp(>2k zu=7wOx(T#PooIlnWZnr~IH$~8ptS&^XjG{JXSs+UZ9uednwY4PD0uhrc}k&`1$H9R z#)_(Wdeblbm=TCKg?0P9s2RBk)xICVeR?L@{XYu9fCBH;CRFY79~dJ5OCb4QcHMy; zs}roxn2Glkjr)k@pElBfN#nAZh{*g^My9GiRP=k(3d_H9 zj#9mttO?0A_y5VL2w1&JRDxjsD^Rf$IA_?j67}z#RU)8Az+J`j?_2>e3S2r9o2b9{ zRTo1F$!7-BWKfp7p?`)-Dfs&`3Ge10?^BDT1g}Pd)=tQD;5;Hi~r6I z0*^43>RkIDdRjm)k)T>5{(J7(8*mPXTj2ITy>OuD(VDPG|7B_l7>Vdi(~9vw`2>O1 zWs;NA1pmp01tL-yQAr8iU%l9J0b#_9oSpwMwikX2TTQq4iEohY9G|y zGJ(mu*Z(260YFzmhe5Xa&%i;zI%GB>lmE+QPHHAzF9Ua#>t9hso588{(BWVI+=3mr z{wQ0rTpKysl1I{v?g}@&!J?tqV0FrL9q6ZvVzTbUwa^CjMdpLV| zEZ@U$eA2l|gGaD3cpf+uAmA>aervf5&N zR8+_mL_HAgG*Li3__RxdLXyyi4fDNATw?xR1~xRNpa1c^+MMSWr!a_UveLS*LIHI# znnWEJbpxE-B`g^xQl@}97}x#VBPbaLWYA;QvW zbHF_S5e22CFHh+3_LG6&RyP||ZROhl+<}9rL>4qB_(w*QC`_Wy0T^lMFr(B!@R9B? z7i#b6O)-io93yDhWx>gso{0xqtdyp(k@c)=N9WC5JFqiB(N1RK_t4`cpkHw8oKK-9 ztNRQVjXt1|MxjDUvqn(TmXM>cTDwA}Pw{X2b?C6M;y|_uvGlou+d&2T*a#X#P?`%| z8+G<7h^9?e?F<&GDfrnGSYXHZKF)~fPLmZblZEOlRq69mydCtV>ck~%sW}RGr-qK_ z0Wd+n7c-B^L={IlCEkmh{{oH~z!8Bwww(9>oG2papbRFeY|1Hp$1qU5HYi_3 zQThrfsW(}%vskExqdE>^X<`(3JBYTRJ)5RbP8stGZKXu*<$y{>O{_DRCUj&@uJc^c z?bsurOSAfxl%rtXWOWV{n~6uF&>1WpHZmuE0VD@Vd}*?J7M7#%=MpFx0LgX+mxhjf z_zx2RvTL#$3e8clxBvoGR6D(i1SnH;2})3U_XWP2dCLfD6_leec>yyeAV$IJpNyx? zWYJH?eJ=mLUnZWhQfIJY=*Y_3)CK8_>!<;40d4j9~_Z=oGF=TlRt7JAg zziE6TxZjOmt(%V7lFmK!k9zTm-t$sZbv z$4wDWYtjGuf?)m=K#b{VFHjW#rQ0`Ifdait_u^dd2&#khAe51cG)$rk z#E`!Fb(=46-5q*+Ji&e+w0Vqy>rg+1wy;Z_L4+fs7R*La<1QK4r4W{YncJXxP{y8) zVn7Embor8T?U(I#v^d%1A@py&t2rH_dTr~p(F|eoJkkt9YM%fv7KWT-FUpZ8G5c(QIL;mui8*v&GFCCy>W4o zLpWj-zkk_!o{kXu=7o+N5MSI0m{a)G;*30{Q5Mj@@{(Cie<&mtU0FcrQm4SQATmKYX_xGr z4|P5~9$3q`puh+U-$UnlY*g)ja%nH1xDlP?q(Ymbe!shRNyZ)+t&Kl)oj}>c<$@Be z?0L<4J5v+rTLIf}QW-+M{@-gZ5k;GT}R_-{}g>q0;*$3bu z>GT#hlSP++{6JyjR`)IZcgdvDUB!t@d*nuBxmnM=T76a#1PznB(M3uw$9v}!1=K)A zg)SfR*;RltgC-IF2|P@ZIYUqh4Q;Un+I|BK^zipdREU85wXOzGh?0swvVG{w@{l1? zzmqvDrO$c5li!SbjSq)z#pXa{ylGRF?%WN3L;)L4T*xO((aL8zAC6PnM@e4Cn& zgrga=+cR93s*nbTBzrr$CuM4LP#H~QJ!#n3QGGM|trAuUU7$(YD#8wLL;YcYxPBmk z@EVoA{_fE^b_jgS^ax+($pg6~+bCO%f#ruS6GqLnCtkbZx4vbxW;E^>am{3Cf_Ns0 z<&BadQy36x1BCEjWDf6=e-(XR+s&M{7|n)yC|Z&K4v*0kdRw<;$*GQ?zn)HzmHf21Y6I zrXRqr#3iC901+s0U7H*PP(dD&iQ2#e8@{0LNBsnW2$Uas@jGOP0PeT)-@*wj?p)O9 z5Xd|++|Md(MAXsnJncggKzsZ3GC@KTmWNkY3mUH(+dL8$iOhPqN2QR{VRheqA@)4T zq0)OMwv>fLsj$HIInjAQ)F^c1Dbup)IRps^IG{I|aALl}hXOcP4oTbFk*7giC2hZh zBrdeT35=2+%%apEIV7WkGo+o_45OK-^qrZ$0`Cpf##3Pso54V=nLh<+<;Ho&6&(he zR{IW+CG-Gfy>#aW#+m_ag*0*?_9wKX4?T$1v80$yv+W=R3H`_LMo%ORaR; zG$ya&ex64S2q`E_a-!o#VwooH8` zGA}&k6QjrhwV5o@d1!%vN)Yryxfjk1*#{MSC;$fO1;s(V3#d*&spEbb7uPXB@o)pI z=`N!3Iv7_2zlW|QT*B9Yf&(jbq?q`^J0T#ypizUG_R|G35NeQu1VIC(co702g5VmT zfeDEAC4piv)i98J57ONw!uIn*XQcNsGt{GsaGtP{V!{jIeM>>jL_tt$c=wVZg&U|U zEqlugZo)<&jR6dW_tS{w+1DsZ}SCx+(j!$Y&#(3|#7S4R}sM%()EoZn; zWicrT=)xF&8IjDm5hMC3v!p)ZxI;?M`HNCmkM6G)C`4as z2n?a?M`lKvSm*+?2pYa)o`p%W3UP2-n^Kq7HNAMicJMvGsfn#UW~L{_v#grzQcv38 zA~+)GjvfZCJ4bjF+^+HBPl@D|<0pC}2_y87oY~E~)J7R-C(=n6^d8V3>4tbLOKiE2 zeB*RzS3Z(RML&IkJ{q64@7t>E3A4JdDkgh*29*_K!j+xBW;q3>?aPJ*2 zit4<1S&UiU_ZHv1R5vk5PXXtHfEsE#0cAVfvl8@%vP+$I1D(3ypnCWtb8%R_`<=V+l1P!R^$clybQVYluM2)+J2=&STTmihh5WRr{JT2m)3)}#Jzb%e_ zPk`JmD7C6jG&z2G6Ey_zclNiNSAs^eb`d623m_ScY-E3t*bp=uM0h7od6Qi@>TmEq ziL~RM3D*F5sYtW(@L(IKnty-nrJ&n#y}@!XDND#K!bkL9{5TzI%>MGij(l@r%)5W9 z_CFM900ldk6ATcP`owS_Ww$D1VWD(>ebg&*@a6>_RL)Oi12c^T@=^*GrW5OYuIRzj zZ?mPP&F94~B%aPpLJ~J}_!^VcDuw0C5(31acU=J0W%!9D5u;#Nw(ZnoWw&V5-4F{g zf$xe*3rJsF94()Zy-cPjY12xJ&Bk6JeHU{UnEV^+XnKua+D^Q2Ae5vqKDnk-1{PjE z&-UX#s!V1Q-`N4x_t0jF=pOx6wjX=i$Ay9Yh>~Xv2qIg_148Mw^Qe!N%c#fDY7X; z{6mNL?w>qT4~;u)B>sC!1Dpy>K4Ar?nx37MV|i;{hNTtkk*5%D52p7}^-$H7$*7S_ zKEZs9&cSF`>oF|Pmc`=o?u^gVR~FVAq7vTS@>|E5X5dbifgMb~%IG%`{Cml%aBLKkg_dOLP_MU3AgjCZ?cd|DnWGZ@k|M*_u`j~faOBb-h zd@q*u)zY)d)^S^&l*mF#(9;+UXRPA=2uL2!HTmF7P+G;CapP^uOhn3T$Oc!nN8`#b zA&O0&z+%sU9g`)WI3i&zQ|5 zFu{<8ptRgdn5sIIR}w$TdzbfEdly;p?v(lTfb)0}X?eQe7x^bNt_o*@4Ar%Tt(=z; z5Y+IQQL%G^O}Q%QR&k6`llM5iUb!8CPi-smz;T@kb8TTUtNuJgK@JGubcROGT#r|I zIzI)N4D37#UI}>2TQXc&zOh&ip!ovth1rcBdZO|f(2N)b5tGTD+<^CEX2K(GE(vU8 z3XR=Gebone_CJ69CJ*Y-ty{%PMg*MA_G70tVWWUOnrnwAC>*FT<@UgJK7Ucj@jeKe z9ut_fhJazIPDQyLWr4y7FCuB7XpXE$!x!C{xO{`bZe6d&j)b4qmBKqYD z?Dw1Gw8YOuKDoEdi)IF91oLr5k&FFe#AW)UN+_`)y)`1Et-Und0vu;r=yyRKc=0Vj zvVs&D(}_5E4}LGO_X*eOeZQ_Y*^-uB8nClR(BKN%>g-*r^ZFX13u+U0@Wydo9(x-8 zK|kj?F@NAX7k5=6F9=0hkv``oAVlUZ;YcqAw}8Oxu(4Vbt4`L}^1?U4#~D(V7sBvH z_6AcCmz1b>s?FLJSY>^!`f{rP27{e*IRxH=fbmkdBB5$j4|sJ5xOjm*?S-DA`t{^n znX__#{{@naE3hF#ZUK3g3MC%uPq*qq8Ni!%moAJeT>)2i&*w7`ID=W^4eHG8k36d|<8w}=DC5XuG^toMmK>c#wV{jF~`z7lJu1J}-(z2T@ zE(8Ch9IQQ`fIz0W{h@G16EeE0pTpcH0?5rW8u4$*N?2SLlZ5B$UndZw028c;xL?0l z9_8)b@l$wL!))P`s)W_EDt`{K4~C)?L?sa$Jf8p#Pwz;&g!|Rk>5R+01`&?5Ne3$ zgC_I%L4Zs&;-d?WRbvtOS6R3@q61D^(3v%oH?7Qg0)yq{J65q9Um>yX?kkXW$Oq%X zl1E%~-jgW7_Vl1Q~c0{unWnaN0prOGZm0%YpKbQ^BuhH zH)c)qs$T1-L`8fQvAO@YIjrGs+GNCX*Nl(;ubHvh$i=cAcGA$ruFb{7WN!@H+!tCWR})j+!iUSSa+6NbeYJZ>4JXWA`(5KiE){ z*JQ4Y%=MwJWhCoq#jD$rpwC=D3)~A^2?NcQSz6BvS(G|<*P(H+W6-u$y04r~frf5% z4T^Q2-h^zm(dxdOFiAIv?s*&F)^Se`KFgHpavN|7ySi*lAE_Suk5QIi%UbCth&h@` zrg7fCdgf4#^X<{;dzpo|!}n)AT9mOCyFR%VdO8+bA;8P2qolE6k=<<}Kv&r$x^1sImvqTLi8I-db13i%P@-i~C-F*#%r1=NdthzllIb>3Y>2kYHix z%n_ZfRYzBTQ@m4%A8|5sq=yweyOp&sJT!k~$hza6(O^2=+cbE?nxgoTe^{qzRj&b$T z#FgP+uO_%=d&;+fk9+D~=^*d++vi{2^83;O5DX%^_aRL)E=!wZ&#U#TQxu=UH zLxvRYS^aTC&zdXWtk<$){8U9Ab`rZ#Njz!ea&WqyY=^VAI=k~AD49xQmB$|nKIo;dcpF(p7GXe056nAfojqkC|A)U3| ziM$t;09^|^gCYM{$IezSpXu;jWGY5oYq9Ph%R|YQ{?WVL8U0k_*K3w(g|WB5=V$vQ zlN{B1svkf83}(Sm5IQ*F;it^-(GBOP7B##ZmOdE)lmHC5hkO4u`Jzhb^@8nNWH)B6 z+jj*J(9C!k*i2d)K@_GP&SrKTZhnFZeTHeoC;;)JiQRRno4%bu^^hVhFaEeIsn3M2 z$kOkr-(<$Qx|$`9`Cf>R-d(!3kUtAdp5>cX*yrx?AKiOb%2Br3(P!42nEj&mfy!zK zS0}gdouY9SqbcDuB`m4ELb~WeLHTv3?bQf7$}l%}4VY4@!W82>E?)ct=SJ`~MryNz z<5ySLkkh8U$o}R|T%3I&5cyVjlAz)c(-NM$SC;-`K|X_&Icc8yj0( z7kjl|A~+5kR2rYOBdA+ZuXsIGc@vFwgR2G04!)LKJg(^3^~wH)4b@QuA*bEkDcFf| zy^+RrnEo>raTdu?*4j-dm#F-^s;7J()b|-J>x*x@@n^6<^tm3VYp|82}R6XOAu(-H%_~ybdYqgjRzgAO~_9QMD7Ga z%jT`KixFzkJMD;e5vMAuSS;=;@-`)2YU$griC(09T6oJ3DjEe zPU{;z=4zIu6#Iek_6;7WCtpSeRzwcy2d;kJA2F5eIc>uOoHToX&l3mg6=>*cr`fo|>Y`TK$KWGPA68SguM!IaHyB$YhF z9f!)FTgklKX5_<8G5b^EVZ0$pt6Y-ubRRG_{QM}>1$|^3PI(tYC`^sn6kjH5e;95u zBG;2|QDemX{5deYVWqw5*6+@H1AZU(+H`0JPwom2{FI}-o4h5_(Xl(*sQ62V`0duW z+s&!N*DX?9NonS6YgpvDO%`|SW#v>)P2Gy1!TV~MVb~+ZxZG88xkU$wTUb+IN>JC5 z+w6fq>;eLqeoO9;GivGB#ox4rJ94Q;f)l^l?pm+4@;Iwz>(d#Le|EBPb;0C6*nz{W6A)aHoR z>aVnkts-euFI2sELM{GiteJcm26*Mw&wpEd!nXtS^34rBqbT9RJ@Y@-C_Z$~Z{2v7 zbnpHP-6OjwCwyKwiK)Yn9q?`NZjE$o#3S^n_x{SC@!eiNw5*u1s|kOwI`BK`mYt`D zIa{<0=aTTRQK#9}zMc1Ti2jiyCNg=|d4zjSk-NLwCJ~Kb+vbs7bzMgLo%{+#f%JLD zS+U-1DI@1nm6(Ex;C6jb^2Ml7CZ5Eaz?~yU>ONHj#kk)_coz(+bQT(JcNmeFB(@4- z{+MJZU)qjsZp5=Dv7ucnk3dJPf&l|x=wywB*FE!LZ_2Je(@p+Ov(FpMM#|nI_7a_p zd6W7NKU%t1{ZZ?b=dKD~ZXWF`#NwV=5L7=cQ{$}>JP6C^aqwAZ{CL~w>)YpC-HdS! zkawVSH&OvpRq$v>$f^2x}E#JEH zM`zdEc_?cA=cSJRc+|{}*PY`Qtu1Op5)s*OUI(G%?W{eXC%oDL{up!FwL-?E$cp0N zROz;Y-{Yzb8nbR&MeT)TNcr1s6tkWR@|^ka!8 zp*2$_=B~0XX=5GEq>|QOc<8i=xK&beW;>C8KqbB}jh^x~I*Ytf@*}s$uno`S)sLk= zEq%V82}{iuvPExl!O~8Ss>ilFXdRg*n!HT0CO;1?nOG7a_I9SmPipTb(OVQ1#wy!? zP8Nih+0O6%p&sL^ShwxT(m~3~=};T1^m>)5HF#S0M}OMn123;az!wKc3HvvGtX@0& z7MNTEzH0P}e?BnLv%XZP0m5hm_&iwrr*c(%>CaK3Qcbm~x5G+q4>E2%dHIBBrc3(^ z($3o6lyw3d8g$zKc$HMmIm6+24BBoO|Xa>DGeSBMIGD#_tn8QHZp&P94{Lh#PikUTXDGviwZFo&Dat zmBpI!^g~Y0T@xE)!qS2iPidW&tic}d=P{dfKGxPYb1)r|q`!;%qod_c z-W?UDwwNDTUO$ZCi$XqlZd)@6-Z4+gom9VRUuI7-Z@nb^q|>BLO7+=_45yOq3HY*I zx3Q~i!E06?ee_E>xs*AtQeK^`fq;smMgz8Pe_J`d#o3CaQGfK#w0h)Wv8uIo`DR31 z{t{7%b`=;Xs%)*O9&PLu@%$Ds7E!#KDu_7Jm{@p3o^jl~RrsTa8`RYF?~cC7`lKtF zRc=hq{yvPt9szH}P1=&6Ht_xCNI#RBvA1B}a zww5RsuLyuo-ZCmH#@_`Kz z9#@~5Y}7xwmV3Qk?nD^Ijua|b(*$ItI~SsjrA=E2)%ZN)C|Y~9gFr>Rkb1xqF!}4p z%iRYwQHMYAY6{F=)2@FI>9`@MW0~==8L5Y)OfT4HJ^a|*NUlALCiqO@YsM0&0+|P@ zl?+tnrrdit)6~FQPxifLl?-RWps77HqZuUpFCpTygufWKW_Tg{9-$qo39fQ_Y(6T zRZccWG9RU96imBSGE{E6mu37;D199^QmZ-GZ-QlUE3GEBeX&eUr1jHRU4Q5m?vz$t zrfMG*nlx9HezjSb=C~!AzLC6)P|`cbcKtkTE#hc9Y>llmKazStx?>!YviPY-(z+v`E2oP#A zmyUn+Jtvn76#v%H4G6lDs(q*&!t7!MRg!VTn;Qsl?oy5N zDF@*v@sJg!+WvLUSeT0OD9|O6nlDa&Wo7k2}8WTkL*SL&IQ4M|8j!g4dOw`HLg8+FwJ1z+FaERNi+X zPP4ZUSMQouJw?=`?T}f@?AzKRjLmslsd>xjfgk$Ip53{*yg0V#rZ~s`VSLK6xj$`H z@HUgqFL}v=7Mo2K(wI^)Iec`1?=(01N7}HorCk=$%7Qj`uS9=0rvnM}(^Df3BnZ!9IX0dhc%<`M&a5wC!!u#M5sw8hdg_f@$H5twIePUk9dRJ@0#=&z!8E2J(^8 zSUoA!iyCp?mJmkj3UNQ%>?#rSR`L+TT2mbz-k6{3t#QNJyd^O(@A;aq_KZS zUq*Fe?&Ap!t9*QmL}ObgK|5V~Rl_c>CuGr557~;=>a15a(b)3Df2=18qri~b@QJ~T zMP5JXFG7=k;yA=h2jY_gxY8*pEbD%vKu6V&lJb6xwNGOzr%Lur8*2?cdO-zm6&dbY z#v&Y}2j^+kdDHSoqv&Y_mXM0}--LXgh24L4><*=havG(jdbK2Q%QpU+Q@BQrdq(+^ z;D-DuOX4d_;t-P2uG$d}c+!jo-B)RYBk>EBaVN~NEp`C0^)$XjF z*53H+J{@O1dG?Ba2Dlt`Hg6XeDg6hhU^n8jLLZ8zVoG>F$ym;Am~g!FahBahJ`}!C z3r+8Q9+E`X5s(_U#@FZMwrFqf`t|$wNwt%=6N{7Rx?B2-rUoOV<|BZzk{-^M)p8u{MVt2jbgMPw61rC?=fT74Mn7g#;r?Rdky~l;%}MJZ z;;>!z=VY&k-lxj=A(p~spYFSeKXz%FvGj^6$jqAhE(%KiMZnLpMZ34H9&pFyjgEQTvn~P|e;W2pOf=fn*csq;C{KwqW z99#qoPICG z$;oMJlqL7qX7Ap2;+2%4H3!R$08a6-fq234hy$1jqK4nkQ; zn`(%1_>UUr=hibjW(CUWM6io>+RJcPZN|9ZX*5L--Z0@&e~RT4DXQ+ND{+oEns-e@ z+r-+HH)dL!q<bd4v<02f`725kQ-*I$fLfw=X9rm8sq+eCJF(?MDj4pr5 z@T?c(^LB4l3VJrD{=*QhCCrTs-P$!=Ig#tquD8yj2@y=-hFsUZD*u|~*S#EUL@A!KZ z{GZSd+<5TOx7G95hdG9|1T-zrgbb1s2cL4wYJZ zd^=V=D)rLhFm1^N>rqSr!)lU7Ax1^J2bXPm8Ygm6PSdmp(HU)9!=+ne6OYeR+4d?% zcn;YsA(Ga%7_S(iN3Cr9gmY3eac#i)XA9pr`A8sRrwInVCWSPW+Ti;WHw4GWi0!S9}N!f{3q9^Km1vPw(k=(`de zv?U6+Y_^WYa%YbpWt^5;j>@m)6zL^YIW@y7Ra%BrFqfV z`sU9GD>qj@Z%#4^yZ=1vz~-Yx+YU39S5e=~kKWz|$U;rA%QiOfW}Iy3w0#~&9={eXqY7gd#-RV|mzmMrBsT4wdf-~F9ot8;Je*f0~; zY9pV@VV^?2KpC58cOD2A2qxlLg| z(jnG)w!jIS#Edxj9z{DYIYd%*G)kMs>-Kh=pR$bG_=3!GzthP*9Y;~)<=>pf0)w8> z>IVY_MvLKs6(3ui*ry{-Hii|a3&rEKVd*5-{jb~FNG+Y*I@srQqv368)0AZ2ad<{% z7<)6C9YE4a~?jmGhwVIC;v*})EQJcU6vgP_J%T-@t153 zTmGUc-oz#t#UEacjR;iEir!tW^uEREwnga$`xzfVFL6zb(>_N>rLFgxUfvwv?2D#9 zzbXXR_1Ll9(;Bh#vgbBV=-T)Y=V;43|f^&cS`uj^U~nc1EA42!o<1{6{fkI`Y_=ZwUFBp=6ta~k_u zJPUr+ODH9p|MoHGnDsGKvo$0!CPD=xNg`!l-}Bym&G`_#`KjAXMTR_TehFhz>LXlx z65kQg!Uu)ihFK3JV}cqC$5rW9lIWapI7gj8X7jCtPgC()f-Fu(hi{iQgWb?4$ zBc`~xre)VW?r4NKmyPeyRotR}Pr?d*4^AH}rv!5ZEVjMeY;iP3td>Fj$@_^|6=Kgd zj*5w-)F}gW3SGI@1HB+iV-XG)3AS;uFP{sq)mZaRV8hvDlkw_th1L2jjxCiN@(VHR z?4{BqiVmBFS8sk#m@IPz5)FSQV)`J*K^=}9S@5cyxlOGx{uUlHtd$X!ltp`sFWLLa}eJ9uNwUHqh5)~jR)MG z(oMZ(CdvEdnHPBg!6E!_RgWtk-DN&^$Qo^@{w*0<~ zqtI>mO7O>_dh<;7?;lCWOfbfl*-9scF)cq<-)VIbpif_>r_3NkCLRjfRnHAcMInw< zTE&-kY?nR-$RXvS?;O9#S_n)?<>%KAYIh)q;OZJnJ47u@u6U+YK=Mu-Y% z5+qp*OzgUS8E7mM_28+g6~@%F@xg|1EQP3a5RvG=oxLij2DM(4yRM=7hy2+xPkl|h z?c;A5(fdM64pXZ6RT|A=T5%qUCmU}Z=u@`ewa9*;a3nXNIJ{-%0#%*@X`7&tu`@dp z;pcLy-fN)t>?m;9k%Vs@xz%NsF)`{kjeKs2-$0e$bCM9yP*hi_fO;CYXjQ6xk zWlx}Jx7Cy-aji<_`=)gd5^eP9A7QKVnc1p9Jx#_Nf-leoib{+FZjWEHcB)Fic|7Vm<>M8U%BOba*uRn{Ie5m zt~H^M-^`)D#yD}P%D+fAOSpU^Qm{8mJVh&kKcnuahQmvC`0~c!-1M&x;Z4=S+`Z8% zh*&kx%~w5+Ow7e!*gj!c^VFKD?AP9L(&GPN>24#w^k*f4Glt`Ct9j796m0bJ=?KA` zyKpa^Ij??1<_AqAN4;?zGyvVwZSaN1Z-Gn#46Fh1936bb1S#NHaB)B~V%$2>TQS#d zI83V|c%bnL6gn*|Q?-iSy>-fJ{)*0V$zx0r!9-?OV%K1W9_AiE?e?^4JHIg2r2psV zAL^t+pN;eeTJs`n%O3B>>c$N_8pqy(gm%_2!8;fc?#Z6@%sJiNo8CiePTQ4GzEeH> zJ7?Yji3{?CW+fo{y6UaJp0K$>g&$72z2^q?pc%C=Pm{UQy;aW(?gR75^7|QA9`wG- zM>J^1-8&Hqzv1C!=pR4-s)JMcEOE8fWzAjr*d4>+2c=->WX}A7|2^*W!x#)JiHC7} zVNTDNRkpX}mgma1KjZPE5A^u5c`fK&t-k`j^&Z~xWhVS8C@>yET~u8kK$Qj6Dr)iF$Hk+IaLrWtv+cE-rity|wfu0)OZuF_zy%Lye^b_#pinQ z`9~z8ck)UyG%Bf%Y>RpZPl<-x* za%vIaQ9X7qQ2)yp$eqfXR7&r!(&_5%$1Z8?tMR((5rrL`y(UZzR_u(u-fw*7HB_FWWXA3UU?=IAg5wNJDh}K`jfhWa&9+Hp#QaIr3`D3+(!VlU(WTN^dZ7N02 z{pQepy`^!D^k6U#WZ`^&U zl0?ogBssH>xqsq*mU03KFi16#byN5~>Yq|9m#O>pX}0V46wwqGoRXyg5W0uTno*-K zQaq^>ODI)h>ea!#VaEi{b`iC&6=dLvge!K`grOnTG{VG`;JOjofYL8KuZ4X~Uouu* zS?zc6hN~*)cOwwgN_usqi3!Xi-fOxIs+k|j(;#?&A+jj+S6?e;>mZk_+R#%sTih9z zw{R%S#rjyeU+vqPbNI37$wFR4&$SV!7iSu?v%M}5OFN~yO7fBDB9*opb237HPi(kb z?7fuqFzWijn~Le6nTaRsjcPaCRU(CLp7^4#{+7qg&)crZ>2g-Zq(VFV9!Tacn@Cij z;p!dW?J!yL9`xRy8i-|H-?ro$<|}n|a%SjVplh&lXLU?81-aKgEm|GMtFVO>hST)G zS}bu(UTyioDbC)TQlZJ!B|&2-@Z}*V1_d?l*bEw){SU}QQv~bKJUOgJHyT!3kX!t- z%_mF^QUoD@NB1oH6F~*xhMPGgFnY*ePPertoYp%_uTGUnsDKAGZacJnXKip zAU`^0j*nzYzBT4fi5@xJ>8UV#y8s`E&}@g?Tu+YQ>+m7#D{Ptz`1R3ix3YeD;$~q^ zZkz|HnP!{ikC;M34m+DBe$UoHTRy&2;7W=P+?qI8N{;h)hVSxpK7)&;4kc!Q|G0b9{E!NQLgk8F@1rt-^@z72z#K>k}*zGI`aPHVO>XZaGBlY}5*7o)3H z95&;ExnBb@lmAJuWN-i5Q!%CR+W6-W1Sk9rl>v}9%R<{Jq8?u6o%=LFdPljv?(2Te zS@Vw^j%G{7(F)qy?*-{?@r8V+LAPq>S4rG*!YgV5r~(ny>FFLMmVx%QvgudsMoXoDYkkYzOG3AhK+ z^)5XAY=_BsjOSpDqvMgdJ7!cYv}8mzH|+QjIO?Jh?$<@dE&gQ*4a>w`yVzwb&0qcE z1ipu)R8!pn(B9Yat>vN=p&#ZB)^$0*qGPj!d|SL)zC0D@gVg$F{SJKt&dDN=gH?QKb_Env*6Q(9WX31nW$-iW9#Qrn?5x)9r2xa{liGk|d z8(1826YDVyh12*?QyO4z$`zizf60WATK+TXJ9_Xe813dx@sC8w3X9q*k3=Wo!jYgE zXKLN2X6&Vg^4_?vjHfv`XZs)iz zW-FscZrZi5DLrJ!YZYqu9&jP@VV3bn*&T-VCoM;wdQ0MMVn%e>^$Q7<)sHkjDrj#8 zM#ZBk(!5SaKWyBgo{5HhATm zWLKlFIV;$d^QHavzwI6b+ z=_R~-vQ@bozD3RMMRO2C&XKwW<(fd&{$Ev39th>y{Y3UeS-LlS!cD~eVr1Xi=voRX zF}U5tFk~Cc7|XS^-J%pS*}9P>OBh1-N)a>J4P%sLvW$^o7|ZxQ!;J6y&42Se?|Yte z&U4;#&U4Or&ujOLzwbD@7%ih~5cWqyNmM{R={KIx)Ar%rHUeCT7JvU6pJ0bzv448i zn5~daqnui`=Jn!U+o##;d!`Y^-~BwXS@RP2?OnohKZcZ;tMsJ0UMUDlRj4Vpao{RII^|ER^%{;+eZ2DO&w#R-hARx_bC^4SY zETSD85$YCz8$lY$33?3BJ~k+(zZ36C(#wZUv@a#?CA3bO#^w|iSYDg`>24u`HGjTY zT_O%YBz%JA)OMhCZv9dW(kS6VR&_%h-&b=={AW>PgP(2P{<6$^NWHkiAIxLnO0yB0 zUrK9zBGid08*R0%zfVA3*$aKHp&VA$n;2i8d2}}<(64ehzVHlxGO14#P6Y->?%Bx6 zROWhV$%?o4^5{wQ2_va~&6h`F@l=Ow;eCB|P98~QOJX`#Xn#mi=Z4cI(NLEcAA)@O zHmT9>$N<>eZeuh4MdjNB1-^URreOkA@m?q*rab(K;*SHVh5lP7F%PZl z_&0#WjQZ%UE&Y*e>6OdJ#Kp$R(`@y>yw4Uddv$L%&x?uu?uxd9FY;=7Ui^Eaa_UxE z)yEpRHU;BKLw{0@EGWRjU4bW7%2hdpkSt`h7-UV2uSYz%i=jo2#`)yiJXu(FX`0>q zEGYKq(B?#VV@ekE_ea0mn4RxHZKTA`IZy}2?vD(S|Ae3vHyDZM~ zjEv_}R!P9qo#_fD^!Y!EO<~lx=RKtM-gN`{xF5QFGyac{UsW80UCH~GKD#MGn^fX* zrQWx`6ZL*}q)*LiwYD?4ShoClWgenHVg;md8rs?jz&F?Y9yVrU?j`O(nQs=uYY8CB#%+pDOj?f;Lz|n zc0{$h{q9@wKARdn|L&>uUdC$XMADe6x-^MEF*_5`+-6m#4)QalG`&y7&KmmfMsLqm zIyAqp9bjAu{c$eM%5g2i#_j{kF2~S$K*Ljx2fYZzCB4q;3oO*KatMp@=qztQfkgh) z@}Jl6z%|$!_yA?<8%{@xs+w4T3pcu1TswMYc&eGs@`02|?_BH4(v4-zQ4DhSzkIXe zaH_8i@r?98d~1`ZN?%EJ4oBEz6@Kb5L_4jlsFns-myh%Z=w!96=+)|kCbxFfA68Xd zQ>M^B;2Edkqd-cajJQm>l>Bj_jn24`=@KYf8Cu%?;pe6=Y)=W$ir-FYypia{80=3e ztkPK2-hvZnr+|2N(7s{fEh%>f){PvqT9lvjzH=QBkAdd6@W6lN%gvaO8iY?o=O2JO zsvG_`_Y_7>gBO;hF8}T+G~*9zR4vr0QS~w!`gVQZy)o=^Q;XcK7RW*l>dniMjeZY%GGArj@-}c&nqGV(`SMDJu2P)g+bP(|xyRH~pKGL`zYp&T>g5 zD}Uj=R_I}O0$yV*2ILCD!z^m2N9y*D3Ne$K#~;QIRmx8sj<2aW{l5KG+ZQ=&_>2eb zM0F3TXL*n3SN}|Yrwhy02r`W_a(THeI(DQ!W#FD1AH{4TNr&+&5B0RNejuznfh>QA z^0xJ%9maNi*~lSXr@3S$YcFBpwS`EdN}oZ<6?0Vf;y?HA=TP}Rog6MI?1DWh`f2oj z=t#=ab-b$644q~11I`RsG%XLVOzZ zb1-wsRTo*E{>=h(*j?N%A{}o z;teMmbGcB}!?-%8?Mg29(GpBhgIy>nX7A;%_cc-0`7XllP=sztPG^vB#TE{N=?)pL zxpXaGxbn=8fd?U8NvNoZJlffFi?nae@}oXi0c1189m6gzUEwa@HF?#deqOD9ch(Ns9> zNWs}K^i8paT7P&8?|Uphd}O%+?HB7zwQ`HTIf43M6yfN*h$=`h!Px02?fXNcbxt=2 zd8NgN5OB>)%J1ana7by(K2JN@jk2!5^~e%0m%4_x&!y9&2Of+!7-7s^CuZx(_vmQ; zfcg;Jo{nkr9M9nEeO#274w3yT<|L7QXG>e>YNX*?zg+j`)!?xt2~~J~H5D%Y*qBls zW|L1W^!NR_AD{j%vueGI{<0a7%qv*)Tsn_jm>3&DBZg+-6ijZ_NML8ts1u9YDj>$I z_DX~#5d&TRd@|AS<=2o{{t9wH^je6_FZb30z6d<={Fe?|G8zQ6k0m%JNtYqpH6Mn%-TDYX3{p9wi&LA7`ExfI3a`X^jcZM#oD zU$S<#welN;bMH?}Tyoj-^v2^3z95LBAt~Fv@3$VE*nI%iE0q`zmk)z4OhX%kgQ^{` zOZ|vG;hZYFq@baW7c!$fIOxIsfgh{mfyZea5WwnKrU^goAbpEklXg{GTy7BY<~E;Q z4A`eF`IyLewIb>U7lN5|?cOi8c{claC#xEOq2`l4<&@f$5jCt=+oR_f=$zWn2Xghk z3cXO<^5Tjo&g5tJJS}|Fq3Ryj+HsM9DC)BSuPt$UpSjB4 zPb0!$z#0pl&Az?399i0(Qm15pvIf}I)nf?1XsZ}}0MoYTQkIVHR?%Y<44(kDAWd`q z*BTzi8#v_<#_>kcy*ZPTNV%EdX|h7xP#{BE`!aFmbs|IBo)XKC_hUQ@P{}F{9ZXg7 z4sg(y_?$IF`sbO!G}IV_g8ePqF|bZ-=gKHSPZv6To5-|FmT)_!O`NqyyDHAj~@uW3;W z7Q$==*X%kjUg)=1jY29T4Cao=k(5W9ArrHkF+X$ph!ZsTU>EG->WnFi#Ko1ml+SWp zh_ws(R%hadyxYCKsh;M{*FmxyWMDe5T7#R&3OxO(OYGhB;Z)*q}(=TRmWvRVMeM#~WylUadj#V?dP_ROzv z%l%@}_Mt>T+oZTV@W$a@nb3vQlIu~}%v)O%qBn1jsfUmqhBBYIHGy6HA%^ZgHMxSW z871c`iZ?g)!1*hSG}1xfTs#LFBT%998&7-~#i^N|6+0(ZjK0o*XG}IYW2XA5+a6Z? zO~NVl8_z_%WJ<*&BdBj7Ykw-NN_E$J)cS7btJaYuo#vScHzGgSiUq!her~?s!i`_b zFB!Q~QPmSIpc>^$zHnm4ipitWR_fcL5g4PL)&n{e0mnd{O3Urx|V9MvgkaL%a}_kq6n-0*MQiskFN%I8&!U-X-hRfJM#l%#2nQMKr2B!%CYY!ESb@`N#29HGIr3Gk zG5uY)JoeK%3Z}SjpX8Dl@x0%uW?g}ANZIDKyyK57wda^Mtt-!!Z*F+jN4oJ}QZl!R zr3}Z%P{eR*txwDzh|{M~PmRQy+B#i-HWxEonW6HqE|oDe5|o6qGPYksb~kmMz9YQvqVHFo zQMoJ`av;M$cjei!%IExyD^C({TgaZXXj`eX3`rW73VjqmyIIs;y5gla9h6UQeJ(sV zg`>WLV3wX}F$2<#HO4;$DP$aC9`LatE#3HaZw%D?0NgG~v#xApjef!Hiq~89_w#S0 zZ)E~xdm@}O_v%6YXtBMgwdqr=k~#}6a>cZ#N)&y1WJ!6|1BW~JP#}6FJ;>rNuTMSp+P;-QYFV6gB{f5}&yIUBXoulr1QeiLJQ=1=^c3rs0`;UfX*E!yVJ+hDZ?)NO$UHxTlROmlf zr^h#(eQhxgljNbWK6+97E&cYBy;coT!4cfW9pq;kv-wul044Q=^IjJMlb&>m)Cn0QvQ)Y|XJ18FTk4cLa`^-Z zku?y{1Fy~0OY*&^9#Xb-7I@PUKK8D1r7x_2A{ad!aUwk{u~LlhN^6T-NHTX5qb7oh zgHnG#MAc{&#e(e{&*zSdRP| z@guzPMQP!DooZ-}%j%b|;DZWDOD?NQpQfCbrk#Nf{SZe8GD&mEkv_WV#XIPumu{T& zWou{xGknHRF0`7)cfW=t$y`Z|K5zT}KU0VTa+DU|^XV%iS5GO+>G3uqlM`EQ803!F z>U+b3k}5i1Ca=4Zi?WorsAMiG!yi9!eJt^Mi>^Sn4CC3D%>XUll*(X4{Df76eSh8% zD(fd%a)1_C+w7x<6`k5pNUSzkl3s@2Z9*9-{ChPtA$_aor*Pa;oJ~}Cn7z;SEI+<0UUu%OsmvG&465#pT0o_;~m_Ws=^s za1hjfuzuOf2U3oTd$tC~5qzRGciw`}@AUshssF6&Qp#WH6>p0<#0Cm+7?R7PXj#$h zz9HsaSow=QD>FpD{7#1s2-G(!0$FZsr0?mE%j8?_-AgD_&4C{0+$>dXYq&`T2dqBk zs*hiCDUiksri+-CtdZLd9%@_&CzW0gP$;p3mAZ;h;|iijs}TeQOF+(TJhcI~zk3i%S(S-`~IKIe`zyIWUI+ZJ5XkE)3$d=c1b z#S#sbF{ag32gWbgf#drcNiHyD`Pi14Y^=hEec!!FfGSusLm;v!3SR+LiQD5p zzA#tSZdm!D8rt~mSTW|iXY+~2IqP|w=Xc5S4JLH)R|=fVCkk=K?LhJ+BhM@H2LrYR zvO*i;Zu)wPc;%xx$iBFpen2JyXjjLzNO_4LQAhB~YB|WKoC$J3Fug95${1Jh(Bwjx ziNPJu?6ih~Jn3F(pG*XqSc_=NkLMyUOaljdo66kf8saJrK&FAYe@rliVD12W?hHtYd^9ZS zVx4s8XvD%zfy#o1w)%V7n8b>(8*~agHkXhNtgXL*FT!=!Y z-V-eX;@hj;dFiM7NNwsk3C-Nl?d5$_I}}totkr4Vqg5xeFV$!J{^{ zGBmJ!;KePj_!y8S_Ugu$@{pEUg56LhwA~j2>c$FW4?k?2ZDwxZwL0IZP2u(uB+{+U z0cqF$WNfU)*xx<(geJZLq9ImmRW@-1P@J+uxBIgEAd?IvLaPZGr-(241cF?>hklPA zo)+@24GtQ>L|@7$9%fT&8!s43Nvu&_*K4YZJBlwcDfwgsgzc5EA40Io26%emCx^}R z>p_vkHkH|Wx`VRhtbsk%ThPfMz}wN_%cEK`$Xj9PIa*4ir`J^5Ta8&CA*{|>_Ws)Y z0p(Fv_S|oJ<9t&6kr<>K2w8Xj!pQws{f|BZ3aG?-&zthSk-u}E2Yn!B_0m4Cq8g@u zY!auq`tSCCFB0?Q>+?@DRO!v*?4WrWP%|CO`Kendm92NgrfW9DM|L+Sp47Mqym397 zEn}O*I+z>!un~7#2vAxX85LU}w_{qA+)%@);P>a z*gh$@YcREH|G^GZLlF*hMIV~z-!XBgKet7lVhc9}@NK`m8w=LFF$Wfi0}Ba(@=gKl z`UN&8OgyaI)N zW?dJ)J9f{c&fIVt-ZFE{deE{Pq|JzwB^u-M-(p$9CZz+DlOXWt-j;HXPdg_$zgMnpk|PljiWC{s?|l z-kmNNM<8<8hu7z#2p{l>GS4T<>|S;hKMHZD{~Jf3>|S<_i*o3ohw+7cqU`Qv%J@id zn(U4vU_y3Lp*E~52@#K7^iOk*a4u) z&qa~ouh5yz1}67)H-13IqTDI3(2A{zu3Vd`;VUWQ}hgSj&!MN4AXOO9#8TG(Z;9c2K~ zsQzk#0=0kbh?GRRg41YA!5SO8;FjJkl zEFFw?Ac?l!SFOC+bJ0m|y%r?T!Z48`kq^4~EAIbTItjXBv3@gU$n1<*k}D=}$oFSP z9%<9tQT-DrzMtE_gl3~}bLBX`%b~}Gw-MAv!G$XB6MkJlv2l=n6OdhB=7Ah=62gMJ z1lV6WiuQXAV$WVRovU_GS#ZlvI~mBIPRHAba)W5FhRIx1~M83q~c%{wX?~)JQ zCa_fnBziDqe`O$KLl0kfRlir#<949-5^&76e-YkK1u3!7>wc5A*V1IV{mi!;SA(gh z>J&jh?pL7cBl&B$QuYIs++9S_Y+NBErz$g)#%co!3Lv&&gM(g8ZuhZ)Ko%a{;HD4- zk;H!iTKbhBHp*UW%pF~T&ss-}m{{2JF*y{hdxmkkGF3m@2pv^jn@+IyY*ku^8ma$B-=J zDAl-3s zq=1}c#J2nQXssA=H5_59I|$SxLy#g4cYQT>DZdl=m^*AJyXehBcwmb$=IA1bR5dc2 z$d6@YaAd~w!+kEw*?hwwj=*GVYwWL-%AwnGRCDxY#8JF&9KoEUMxW8N z)-6uEFka{huz(^s{5A2+cu+?pg zl+XYCGm`?vX#br%9PvN@%+^@M8a?xY%21$Ifqhz?$UDM>=Z$_c#Eg~6PB!#bc|6n7 z#++gw){uJqD|?Z`?8#Nfa6+U(JS`bA%pNS$ilK9dABHyq*BX?YvPpJ3=Je1w=QgFy z&ZMyd*yC%_2=?`%j|C|zOJ$ezd1xSJ%f5WuxK_%=xJR*In&?}wdR22q1o;nDI zP0GS=5(Mxy1J3?*ih25-zmY>n{6FksRRyu7{|`H<%NF@)2{-nZLo$KxGUdskhyCwu zbxJYj6xJIpSzJDBv_a>3g1X>gcos;-?;srw&QaGS)q1V_hWc^ru|j$Lyh*n0`rCzB zHgDCevWbr%Ido$hhadLe>Tp@c>o4`RfKP+Tvp_Uf>qiW+yrJ>$ezH5T-FQ?h^)F{% zy2kd{KyUVJmnO4(bkAZD$H;?E4^;|X<;Q9`5&n)6Hx6>?dCz=gh%U=WJ~ne>kKp%v0vXk^ z3QW58m}($;i?r>S1vUV28pf}%*@xHQ;>d#8nw*>vdw~NS_XKk16{sB(p{Y0=xD$+I ReJK)RamM;|iJ9Bq{|9*oL=gZ0 diff --git a/ext/src/zpages/zpages_static_files/tracez/index.html b/ext/src/zpages/zpages_static_files/tracez/index.html deleted file mode 100644 index 061c05e920..0000000000 --- a/ext/src/zpages/zpages_static_files/tracez/index.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - zPages TraceZ - - - - - -

zPages TraceZ

- Last Updated:
-
-

-
- - - - - - - - - - - - - -
Span NameError SamplesRunningLatency Samples
- -
-
-
-
- -
- -
-
- - diff --git a/ext/src/zpages/zpages_static_files/tracez/script.js b/ext/src/zpages/zpages_static_files/tracez/script.js deleted file mode 100644 index 39ed21f13d..0000000000 --- a/ext/src/zpages/zpages_static_files/tracez/script.js +++ /dev/null @@ -1,258 +0,0 @@ -window.onload = () => refreshData(); - -const latencies = [ - '>0s', '>10µs', '>100µs', - '>1ms', '>10ms', '>100ms', - '>1s', '>10s', '>100s', -]; - -const statusCodeDescriptions = { - 'OK': 'The operation completed successfully.', - 'CANCELLED': 'The operation was cancelled (typically by the caller).', - 'UNKNOWN': `Unknown error. An example of where this error may be returned is if a Status value received - from another address space belongs to an error-space that is not known in this address space. - Also errors raised by APIs that do not return enough error information may be converted to - this error.`, - 'INVALID_ARGUMENT': `Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. - INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the - system (e.g., a malformed file name).`, - 'DEADLINE_EXCEEDED': `Deadline expired before operation could complete. For operations that change the state of the - system, this error may be returned even if the operation has completed successfully. For - example, a successful response from a server could have been delayed long enough for the - deadline to expire.`, - 'NOT_FOUND' : 'Some requested entity (e.g., file or directory) was not found.', - 'ALREADY_EXISTS': 'Some entity that we attempted to create (e.g., file or directory) already exists.', - 'PERMISSION_DENIED': `The caller does not have permission to execute the specified operation. PERMISSION_DENIED - must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED - instead for those errors). PERMISSION_DENIED must not be used if the caller cannot be - identified (use UNAUTHENTICATED instead for those errors).`, - 'RESOURCE_EXHAUSTED': `Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system - is out of space.`, - 'FAILED_PRECONDITION': `Operation was rejected because the system is not in a state required for the operation's - execution. For example, directory to be deleted may be non-empty, an rmdir operation is - applied to a non-directory, etc.`, - 'ABORTED': `The operation was aborted, typically due to a concurrency issue like sequencer check - failures, transaction aborts, etc`, - 'OUT_OF_RANGE': `Operation was attempted past the valid range. E.g., seeking or reading past end of file.`, - 'UNIMPLEMENTED': 'Operation is not implemented or not supported/enabled in this service.', - 'INTERNAL': `Internal errors. Means some invariants expected by underlying system has been broken. If you - see one of these errors, something is very broken.`, - 'UNAVAILABLE': `The service is currently unavailable. This is a most likely a transient condition and may be - corrected by retrying with a backoff.`, - 'DATA_LOSS': 'Unrecoverable data loss or corruption.', - 'UNAUTHENTICATED': 'The request does not have valid authentication credentials for the operation.', -}; - -const details = {'status': statusCodeDescriptions} - -// Latency info is returned as an array, so they need to be parsed accordingly -const getLatencyCell = (span, i, h) => `${span[h][i]}`; - -// Pretty print a cell with a map -const getKeyValueCell = (span, i, h) => ` - ${JSON.stringify(span[h][i], null, 2)} - `; - -// Standard categories when checking span details -const idCols = ['spanid', 'parentid', 'traceid'] -const detailCols = []; // Columns error, running, and latency spans all share -const dateCols = ['start']; // Categories to change to date -const numCols = ['duration']; // Categories to change to num -const clickCols = ['error', 'running']; // Non-latency clickable cols -const arrayCols = { - 'latency': getLatencyCell, - 'events': getKeyValueCell, - 'attributes': getKeyValueCell -}; - -const base_endpt = '/tracez/get/'; // For making GET requests -// Maps table types to their approporiate formatting -const tableFormatting = { - 'all': { - 'url': base_endpt + 'aggregations', - 'html_id': 'overview_table', - 'sizing': [ - {'sz': 'md', 'repeats': 1}, - {'sz': 'sm', 'repeats': 11}, - ], - 'headings': ['name', ...clickCols, 'latency'], - 'cell_headings': ['name', ...clickCols, ...latencies], - }, - 'error': { - 'url': base_endpt + 'error/', - 'html_id': 'name_type_detail_table', - 'sizing': [ - {'sz': 'sm', 'repeats': 5}, - {'sz': 'md', 'repeats': 1}, - ], - 'headings': [...idCols, ...dateCols, 'status', ...detailCols], - 'has_subheading': true, - }, - 'running': { - 'url': base_endpt + 'running/', - 'html_id': 'name_type_detail_table', - 'sizing': [ - {'sz': 'sm', 'repeats': 4}, - {'sz': 'md', 'repeats': 1}, - ], - 'headings': [...idCols, ...dateCols, ...detailCols], - 'has_subheading': true, - 'status': 'pending', - }, - 'latency': { - 'url': base_endpt + 'latency/', - 'html_id': 'name_type_detail_table', - 'sizing': [ - {'sz': 'sm', 'repeats': 5}, - {'sz': 'md', 'repeats': 1}, - ], - 'headings': [...idCols, ...dateCols, ...numCols, ...detailCols], - 'has_subheading': true, - 'status': 'ok' - } -}; -const getFormat = group => tableFormatting[group]; - - -// Getters using formatting config variable -const getURL = group => getFormat(group)['url']; -const getHeadings = group => getFormat(group)['headings']; -const getCellHeadings = group => 'cell_headings' in getFormat(group) - ? getFormat(group)['cell_headings'] : getHeadings(group); -const getSizing = group => getFormat(group)['sizing']; -const getStatus = group => isLatency(group) ? 'ok' : getFormat(group)['status']; -const getHTML = group => getFormat(group)['html_id']; - -const isDate = col => new Set(dateCols).has(col); -const isLatency = group => !(new Set(clickCols).has(group)); // non latency clickable cols, change to include latency? -const isArrayCol = group => (new Set(Object.keys(arrayCols)).has(group)); -const hasCallback = col => new Set(clickCols).has(col); //!isLatency(col); // Non-latency cb columns -const hideHeader = h => new Set([...clickCols, 'name']).has(h); // Headers to not show render twice -const hasSubheading = group => isLatency(group) || 'has_subheading' in getFormat(group); -const hasStatus = group => isLatency(group) || 'status' in getFormat(group); - -const toTitlecase = word => word.charAt(0).toUpperCase() + word.slice(1); -const updateLastRefreshStr = () => document.getElementById('lastUpdateTime').innerHTML = new Date().toLocaleString(); // update - -const getStatusHTML = group => !hasStatus(group) ? '' - : `All of these spans have status code ${getStatus(group)}`; - -// Returns an HTML string that handlles width formatting -// for a table group -const tableSizing = group => '' - + getSizing(group).map(sz => - (``).repeat(sz['repeats'])) - .join('') - + ''; - -// Returns an HTML string for a table group's headings, -// hiding headings where needed -const tableHeadings = group => '' - + getCellHeadings(group).map(h => `${(hideHeader(h) ? '' : h)}`).join('') - + ''; - -// Returns an HTML string, which represents the formatting for -// the entire header for a table group. This doesn't change, and -// includes the width formatting and the actual table headers -const tableHeader = group => tableSizing(group) + tableHeadings(group); - -// Return formatting for an array-based value based on its header -const getArrayCells = (h, span) => span[h].length - ? (span[h].map((_, i) => arrayCols[h](span, i, h))).join('') - : 'Empty'; - -const emptyContent = () => `(not set)` - -const dateStr = nanosec => { - const mainDate = new Date(nanosec / 1000000).toLocaleString(); - let lostPrecision = String(nanosec % 1000000); - while (lostPrecision.length < 6) lostPrecision = 0 + lostPrecision; - const endingLocation = mainDate.indexOf('M') - 2; - return `${mainDate.substr(0, endingLocation)}:${lostPrecision}${mainDate.substr(endingLocation)}`; -} - -const detailCell = (h, span) => { - const detailKey = Object.keys(details[h])[span[h]]; - const detailVal = details[h][detailKey]; - return ` - ${detailKey} - ${detailVal} - `; -} - -// Convert cells to Date strings if needed -const getCellContent = (h, span) => { - if (h in details) return detailCell(h, span); - else if (span[h] === '') return emptyContent(); - else if (!isDate(h)) return span[h]; - return dateStr(span[h]); -}; - -// Create cell based on what header we want to render -const getCell = (h, span) => (isArrayCol(h)) ? getArrayCells(h, span) - : `` + `${getCellContent(h, span)}`; - -// Returns an HTML string with for a span's aggregated data -// while columns are ordered according to its table group -const tableRow = (group, span) => '' - + getHeadings(group).map(h => getCell(h, span)).join('') - + ''; - -// Returns an HTML string from all the data given as -// table rows, with each row being a group of spans by name -const tableRows = (group, data) => data.map(span => tableRow(group, span)).join(''); - -// Overwrite a table on the DOM based on the group given by adding -// its headers and fetching data for its url -function overwriteTable(group, url_end = '') { - console.log(getURL(group) + url_end); - fetch(getURL(group) + url_end).then(res => res.json()) - .then(data => { - console.log(data); - document.getElementById(getHTML(group)) - .innerHTML = tableHeader(group) - + tableRows(group, data); - }) - .catch(err => console.log(err)); -}; - -// Adds a title subheading where needed -function updateSubheading(group, name) { - if (hasSubheading(group)) { - document.getElementById(getHTML(isLatency(group) ? 'latency' : group) + '_header') - .innerHTML = `

${name}
- ${(isLatency(group) ? `${latencies[group]} Bucket` : toTitlecase(group))} - Spans

Showing sampled span details (up to 5). - ${getStatusHTML(group)}

`; - } -}; - -// Overwrites a table on the DOM based on the group and also -// changes the subheader, since this a looking at sampled spans -function overwriteDetailedTable(group, name) { - if (isLatency(group)) overwriteTable('latency', group + '/' + name); - else overwriteTable(group, name); - updateSubheading(group, name); -}; - -// Append to a table on the DOM based on the group given -function addToTable(group, url_end = '') { - fetch(getURL(group) + url_end).then(res => res.json()) - .then(data => { - const rowsStr = tableRows(group, data); - if (!rowsStr) console.log(`No rows added for ${group} table`); - document.getElementById(getHTML(group)) - .getElementsByTagName('tbody')[0] - .innerHTML += rowsStr; - }) - .catch(err => console.log(err)); -}; - -const refreshData = () => { - updateLastRefreshStr(); - overwriteTable('all'); -}; - diff --git a/ext/src/zpages/zpages_static_files/tracez/style.css b/ext/src/zpages/zpages_static_files/tracez/style.css deleted file mode 100644 index 9ec75dcfca..0000000000 --- a/ext/src/zpages/zpages_static_files/tracez/style.css +++ /dev/null @@ -1,133 +0,0 @@ -body { - color: #252525; - text-align: center; - font-family: monospace, sans-serif; - word-break: break-all; - font-size: .9em -} - -table { - font-family: monospace, sans-serif; - border-collapse: collapse; - font-size: 1.05em; - width: 100%; -} - -.table-wrap { - width: 100%; - min-width: 700px; - max-width: 2000px; - margin: auto; -} - -td, th { - word-break: break-word; - border: 1px solid #f5f5f5; - padding: 6px; - text-align: center; -} - -#overview_table th, #overview_table tr { - border-top: none; -} - -#headers th, #headers tr { - border-bottom: none; -} - -#top-right { - text-align: right; - position: absolute; - top: 10px; - right: 10px; - text-shadow: .5px .5px .25px #fff; -} - -#top-right button { - color: #f6a81c; - border: 2px solid #f6a81c; - padding: 10px; - margin: 10px; - text-transform: uppercase; - letter-spacing: 1px; - background-color: white; - border-radius: 10px; - font-weight: bold; -} - -:hover { - transition-duration: .15s; -} - -#top-right button:hover { - border-color: #4b5fab; - color: #4b5fab; - cursor: pointer; -} - -tr:nth-child(even) { - background-color: #eee; -} - -.click { - text-decoration: underline dotted #4b5fab; -} - -tr:hover, td:hover, .click:hover { - color: white; - background-color: #4b5fab; -} - -tr:hover { - background-color: #4b5fabcb; -} - -th { - background-color: white; - color: #252525; -} - -.click:hover { - cursor: pointer; - color: #f6a81ccc; -} - -.empty { - color: #999; -} - -.sm { - width: 7%; -} - -.md { - width: 23%; -} - -.lg { - width: 63%; -} - -img { - width: 50%; - max-width: 500px; -} - -.has-tooltip:hover .tooltip { - display: block; -} - -.tooltip { - display: none; - position: absolute; -} - -.tooltip, .tooltip:hover { - background: #ffffffd9; - padding: 10px; - z-index: 1000; - color: #252525 !important; - border-radius: 10px; - margin: 3px 20px 0 0; -} - From 336593bb65f031bb5abd1e9e0b07f0bc5efbb9f6 Mon Sep 17 00:00:00 2001 From: easy Date: Wed, 29 Jul 2020 14:18:43 +1000 Subject: [PATCH 08/37] Autoformat. No functional changes. (#223) --- .github/.codecov.yaml | 2 +- WORKSPACE | 4 +- .../opentelemetry/metrics/async_instruments.h | 112 ++-- .../opentelemetry/metrics/instrument.h | 318 +++++------ api/include/opentelemetry/metrics/meter.h | 3 +- api/include/opentelemetry/metrics/noop.h | 519 +++++++----------- .../opentelemetry/metrics/observer_result.h | 12 +- api/include/opentelemetry/metrics/provider.h | 2 +- .../opentelemetry/metrics/sync_instruments.h | 256 ++++----- api/include/opentelemetry/nostd/string_view.h | 23 +- .../opentelemetry/trace/span_context.h | 5 +- api/test/metrics/BUILD | 2 +- api/test/metrics/noop_instrument_test.cc | 24 +- api/test/nostd/string_view_test.cc | 2 +- api/test/trace/CMakeLists.txt | 11 +- examples/simple/BUILD | 2 +- examples/simple/CMakeLists.txt | 1 + examples/simple/main.cc | 8 +- exporters/ostream/CMakeLists.txt | 10 +- .../exporters/ostream/span_exporter.h | 88 ++- exporters/ostream/src/span_exporter.cc | 73 ++- exporters/ostream/test/ostream_span_test.cc | 144 ++--- exporters/otlp/BUILD | 6 +- exporters/otlp/CMakeLists.txt | 11 +- .../exporters/otlp/otlp_exporter.h | 15 +- .../otlp/test/otlp_exporter_benchmark.cc | 14 +- .../ext/zpages/threadsafe_span_data.h | 75 +-- .../ext/zpages/tracez_processor.h | 27 +- ext/src/zpages/BUILD | 2 +- ext/src/zpages/CMakeLists.txt | 10 +- ext/src/zpages/tracez_processor.cc | 59 +- ext/test/zpages/BUILD | 4 +- ext/test/zpages/CMakeLists.txt | 14 +- ext/test/zpages/threadsafe_span_data_test.cc | 2 +- ext/test/zpages/tracez_processor_test.cc | 304 +++++----- sdk/include/opentelemetry/sdk/metrics/meter.h | 3 +- .../sdk/metrics/meter_provider.h | 2 +- .../opentelemetry/sdk/trace/recordable.h | 2 +- sdk/include/opentelemetry/sdk/trace/sampler.h | 2 +- .../sdk/trace/samplers/always_on.h | 11 +- .../sdk/trace/samplers/parent_or_else.h | 4 +- .../sdk/trace/samplers/probability.h | 11 +- sdk/include/opentelemetry/sdk/trace/tracer.h | 2 +- sdk/src/metrics/meter_provider.cc | 4 +- sdk/src/trace/CMakeLists.txt | 5 +- sdk/src/trace/samplers/parent_or_else.cc | 2 +- sdk/src/trace/samplers/probability.cc | 122 ++-- sdk/test/metrics/CMakeLists.txt | 5 +- sdk/test/metrics/meter_provider_sdk_test.cc | 3 +- sdk/test/trace/always_off_sampler_test.cc | 22 +- sdk/test/trace/parent_or_else_sampler_test.cc | 6 +- sdk/test/trace/probability_sampler_test.cc | 4 +- 52 files changed, 1169 insertions(+), 1205 deletions(-) diff --git a/.github/.codecov.yaml b/.github/.codecov.yaml index 354ed22dd4..3389f63841 100644 --- a/.github/.codecov.yaml +++ b/.github/.codecov.yaml @@ -22,7 +22,7 @@ comment: # Relative file path fixing. # CI file paths must match Git file paths. -# This fix removes the "/home/runner/" prefix +# This fix removes the "/home/runner/" prefix # to coverage report file paths. fixes: - "/home/runner/::" diff --git a/WORKSPACE b/WORKSPACE index 9a8ef94268..9c477b2b43 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -23,7 +23,7 @@ http_archive( name = "com_github_grpc_grpc", strip_prefix = "grpc-1.28.0", urls = [ - "https://github.com/grpc/grpc/archive/v1.28.0.tar.gz", + "https://github.com/grpc/grpc/archive/v1.28.0.tar.gz", ], ) @@ -81,9 +81,9 @@ http_archive( http_archive( name = "github_nlohmann_json", + build_file = "//third_party:nlohmann_json.BUILD", sha256 = "69cc88207ce91347ea530b227ff0776db82dcb8de6704e1a3d74f4841bc651cf", urls = [ "https://github.com/nlohmann/json/releases/download/v3.6.1/include.zip", ], - build_file = "//third_party:nlohmann_json.BUILD", ) diff --git a/api/include/opentelemetry/metrics/async_instruments.h b/api/include/opentelemetry/metrics/async_instruments.h index 71504a8480..bfe43015f3 100644 --- a/api/include/opentelemetry/metrics/async_instruments.h +++ b/api/include/opentelemetry/metrics/async_instruments.h @@ -10,77 +10,73 @@ namespace metrics template class ValueObserver : virtual public AsynchronousInstrument { - + public: - ValueObserver() = default; - - ValueObserver(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void (*callback)(ObserverResult)) - {} - - /* - * Updates the instruments aggregator with the new value. The labels should - * contain the keys and values to be associated with this value. - * - * @param value is the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; - - /** - * Captures data by activating the callback function associated with the - * instrument and storing its return value. Callbacks for asynchronous - * instruments are defined during construction. - * - * @param none - * @return none - */ - virtual void run () override = 0; - + ValueObserver() = default; + + ValueObserver(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void (*callback)(ObserverResult)) + {} + + /* + * Updates the instruments aggregator with the new value. The labels should + * contain the keys and values to be associated with this value. + * + * @param value is the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; + + /** + * Captures data by activating the callback function associated with the + * instrument and storing its return value. Callbacks for asynchronous + * instruments are defined during construction. + * + * @param none + * @return none + */ + virtual void run() override = 0; }; template class SumObserver : virtual public AsynchronousInstrument { - + public: - SumObserver() = default; - - SumObserver(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void (*callback)(ObserverResult)) - {} - - - virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; - - virtual void run() override = 0; - + SumObserver() = default; + + SumObserver(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void (*callback)(ObserverResult)) + {} + + virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; + + virtual void run() override = 0; }; template class UpDownSumObserver : virtual public AsynchronousInstrument { - + public: - UpDownSumObserver() = default; - - UpDownSumObserver(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void (*callback)(ObserverResult)) - {} - - virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; - - virtual void run() override = 0; - + UpDownSumObserver() = default; + + UpDownSumObserver(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void (*callback)(ObserverResult)) + {} + + virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; + + virtual void run() override = 0; }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/instrument.h b/api/include/opentelemetry/metrics/instrument.h index 9728bab8bb..2a7ac8b6d2 100644 --- a/api/include/opentelemetry/metrics/instrument.h +++ b/api/include/opentelemetry/metrics/instrument.h @@ -1,10 +1,10 @@ #pragma once +#include #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/trace/key_value_iterable_view.h" -#include OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics @@ -13,146 +13,146 @@ namespace metrics // Enum classes to help determine instrument types in other parts of the API enum class InstrumentKind { - Counter = 0, - UpDownCounter = 1, - ValueRecorder = 2, - ValueObserver = 3, - SumObserver = 4, - UpDownSumObserver = 5, + Counter = 0, + UpDownCounter = 1, + ValueRecorder = 2, + ValueObserver = 3, + SumObserver = 4, + UpDownSumObserver = 5, }; class Instrument { - + public: - // Note that Instruments should be created using the Meter class. - // Please refer to meter.h for documentation. - Instrument() = default; - - /** - * Base class constructor for all other instrument types. Whether or not - * an instrument is synchronous or bound, it requires a name, description, - * unit, and enabled flag. - * - * @param name is the identifier of the instrumenting library - * @param description explains what the metric captures - * @param unit specifies the data type held in the instrument - * @param enabled determines if the metric is currently capturing data - * @return Instrument type with the specified attirbutes - */ - Instrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled) - {} - - // Returns true if the instrument is enabled and collecting data - virtual bool IsEnabled() = 0; - - // Return the instrument name - virtual nostd::string_view GetName() = 0; - - // Return the instrument description - virtual nostd::string_view GetDescription() = 0; - - // Return the insrument's units of measurement - virtual nostd::string_view GetUnits() = 0; - - // Return the intrument's kind - virtual InstrumentKind GetKind() = 0; - - virtual ~Instrument() = default; + // Note that Instruments should be created using the Meter class. + // Please refer to meter.h for documentation. + Instrument() = default; + + /** + * Base class constructor for all other instrument types. Whether or not + * an instrument is synchronous or bound, it requires a name, description, + * unit, and enabled flag. + * + * @param name is the identifier of the instrumenting library + * @param description explains what the metric captures + * @param unit specifies the data type held in the instrument + * @param enabled determines if the metric is currently capturing data + * @return Instrument type with the specified attirbutes + */ + Instrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled) + {} + + // Returns true if the instrument is enabled and collecting data + virtual bool IsEnabled() = 0; + + // Return the instrument name + virtual nostd::string_view GetName() = 0; + + // Return the instrument description + virtual nostd::string_view GetDescription() = 0; + + // Return the insrument's units of measurement + virtual nostd::string_view GetUnits() = 0; + + // Return the intrument's kind + virtual InstrumentKind GetKind() = 0; + + virtual ~Instrument() = default; }; template class BoundSynchronousInstrument : virtual public Instrument { - + public: - BoundSynchronousInstrument() = default; - - BoundSynchronousInstrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /** - * Frees the resources associated with this Bound Instrument. - * The Metric from which this instrument was created is not impacted. - * - * @param none - * @return void - */ - virtual void unbind() {} - - /** - * Incremements the reference count of this bound object when a new instance is - * either created or the same instance is returned as a result of binding - * - * @param none - * @return void - */ - virtual void inc_ref () {} - - /** - * Return the object's current reference count. This information is used to remove - * stale objects from instrument registries. - */ - virtual int get_ref() { - return 0; - } - - /** - * Records a single synchronous metric event; a call to the aggregator - * Since this is a bound synchronous instrument, labels are not required in * metric capture - * calls. - * - * @param value is the numerical representation of the metric being captured - * @return void - */ - virtual void update(T value) {} + BoundSynchronousInstrument() = default; + + BoundSynchronousInstrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /** + * Frees the resources associated with this Bound Instrument. + * The Metric from which this instrument was created is not impacted. + * + * @param none + * @return void + */ + virtual void unbind() {} + + /** + * Incremements the reference count of this bound object when a new instance is + * either created or the same instance is returned as a result of binding + * + * @param none + * @return void + */ + virtual void inc_ref() {} + + /** + * Return the object's current reference count. This information is used to remove + * stale objects from instrument registries. + */ + virtual int get_ref() { return 0; } + + /** + * Records a single synchronous metric event; a call to the aggregator + * Since this is a bound synchronous instrument, labels are not required in * metric capture + * calls. + * + * @param value is the numerical representation of the metric being captured + * @return void + */ + virtual void update(T value) {} }; template class SynchronousInstrument : virtual public Instrument { - + public: - SynchronousInstrument() = default; - - SynchronousInstrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled) - { } - - /** - * Returns a Bound Instrument associated with the specified labels. * Multiples requests - * with the same set of labels may return the same Bound Instrument instance. - * - * It is recommended that callers keep a reference to the Bound Instrument - * instead of repeatedly calling this operation. - * - * @param labels the set of labels, as key-value pairs - * @return a Bound Instrument - */ - virtual nostd::shared_ptr> bind(const trace::KeyValueIterable &labels) { - return nostd::shared_ptr>(); - } - - /** - * Records a single synchronous metric event. - * Since this is an unbound synchronous instrument, labels are required in * metric capture - * calls. - * - * update can be used in instruments with both add or record since it simply - * activated the aggregator - * - * @param labels the set of labels, as key-value pairs - * @param value is the numerical representation of the metric being captured - * @return void - */ - virtual void update(T value, const trace::KeyValueIterable &labels) = 0; + SynchronousInstrument() = default; + + SynchronousInstrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled) + {} + + /** + * Returns a Bound Instrument associated with the specified labels. * Multiples requests + * with the same set of labels may return the same Bound Instrument instance. + * + * It is recommended that callers keep a reference to the Bound Instrument + * instead of repeatedly calling this operation. + * + * @param labels the set of labels, as key-value pairs + * @return a Bound Instrument + */ + virtual nostd::shared_ptr> bind( + const trace::KeyValueIterable &labels) + { + return nostd::shared_ptr>(); + } + + /** + * Records a single synchronous metric event. + * Since this is an unbound synchronous instrument, labels are required in * metric capture + * calls. + * + * update can be used in instruments with both add or record since it simply + * activated the aggregator + * + * @param labels the set of labels, as key-value pairs + * @param value is the numerical representation of the metric being captured + * @return void + */ + virtual void update(T value, const trace::KeyValueIterable &labels) = 0; }; template @@ -161,43 +161,43 @@ class ObserverResult; template class AsynchronousInstrument : virtual public Instrument { - + public: - AsynchronousInstrument() = default; - - AsynchronousInstrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void(callback)(ObserverResult)) - {} - - /** - * Captures data through a manual call rather than the automatic collection process instituted - * in the run function. Asynchronous instruments are generally expected to obtain data from - * their callbacks rather than direct calls. This function is used by the callback to store data. - * - * @param value is the numerical representation of the metric being captured - * @param labels is the numerical representation of the metric being captured - * @return none - */ - virtual void observe (T value, const trace::KeyValueIterable &labels) = 0; - - /** - * Captures data by activating the callback function associated with the - * instrument and storing its return value. Callbacks for asynchronous - * instruments are defined during construction. - * - * @param none - * @return none - */ - virtual void run() = 0; - + AsynchronousInstrument() = default; + + AsynchronousInstrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void(callback)(ObserverResult)) + {} + + /** + * Captures data through a manual call rather than the automatic collection process instituted + * in the run function. Asynchronous instruments are generally expected to obtain data from + * their callbacks rather than direct calls. This function is used by the callback to store data. + * + * @param value is the numerical representation of the metric being captured + * @param labels is the numerical representation of the metric being captured + * @return none + */ + virtual void observe(T value, const trace::KeyValueIterable &labels) = 0; + + /** + * Captures data by activating the callback function associated with the + * instrument and storing its return value. Callbacks for asynchronous + * instruments are defined during construction. + * + * @param none + * @return none + */ + virtual void run() = 0; + protected: - // Callback function which takes a pointer to an Asynchronous instrument (this) type which is - // stored in an observer result type and returns nothing. This function calls the instrument's - // observe. - void (*callback_)(ObserverResult); + // Callback function which takes a pointer to an Asynchronous instrument (this) type which is + // stored in an observer result type and returns nothing. This function calls the instrument's + // observe. + void (*callback_)(ObserverResult); }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/meter.h b/api/include/opentelemetry/metrics/meter.h index 42c189a6dd..19439da6df 100644 --- a/api/include/opentelemetry/metrics/meter.h +++ b/api/include/opentelemetry/metrics/meter.h @@ -10,9 +10,8 @@ class Meter { public: Meter() = default; - }; -} // namespace metrics +} // namespace metrics OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/metrics/noop.h b/api/include/opentelemetry/metrics/noop.h index 3695277410..b5e8988f92 100644 --- a/api/include/opentelemetry/metrics/noop.h +++ b/api/include/opentelemetry/metrics/noop.h @@ -4,25 +4,25 @@ // This file is part of the internal implementation of OpenTelemetry. Nothing in this file should be // used directly. Please refer to meter.h for documentation on these interfaces. -#include "opentelemetry/version.h" +#include "opentelemetry/metrics/async_instruments.h" #include "opentelemetry/metrics/instrument.h" #include "opentelemetry/metrics/meter.h" #include "opentelemetry/metrics/meter_provider.h" #include "opentelemetry/metrics/sync_instruments.h" -#include "opentelemetry/metrics/async_instruments.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" +#include "opentelemetry/version.h" #include - OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics { /** * No-op implementation of a MeterProvider. */ -class NoopMeter final : public Meter, public std::enable_shared_from_this {}; +class NoopMeter final : public Meter, public std::enable_shared_from_this +{}; class NoopMeterProvider final : public opentelemetry::metrics::MeterProvider { @@ -46,359 +46,262 @@ class NoopMeterProvider final : public opentelemetry::metrics::MeterProvider template class NoopValueObserver : public ValueObserver { - -public: - NoopValueObserver(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/, - void (*callback)(ObserverResult)) {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual void observe(T value, const trace::KeyValueIterable &labels) override {} - - virtual void run() override {} - - virtual InstrumentKind GetKind() override { - return InstrumentKind::Counter; - } - -}; - -template -class NoopSumObserver : public SumObserver -{ - public: - NoopSumObserver(nostd::string_view /*name*/, + NoopValueObserver(nostd::string_view /*name*/, nostd::string_view /*description*/, nostd::string_view /*unit*/, bool /*enabled*/, void (*callback)(ObserverResult)) - {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual void observe(T value, const trace::KeyValueIterable &labels) override {} - - virtual void run() override {} - - virtual InstrumentKind GetKind() override { - return InstrumentKind::Counter; - } + {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual void observe(T value, const trace::KeyValueIterable &labels) override {} + + virtual void run() override {} + + virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } }; +template +class NoopSumObserver : public SumObserver +{ + +public: + NoopSumObserver(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/, + void (*callback)(ObserverResult)) + {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual void observe(T value, const trace::KeyValueIterable &labels) override {} + + virtual void run() override {} + + virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } +}; template class NoopUpDownSumObserver : public UpDownSumObserver { - + public: - NoopUpDownSumObserver(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/, - void (*callback)(ObserverResult)) - {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual void observe(T value, const trace::KeyValueIterable &labels) override {} - - virtual void run() override {} - - virtual InstrumentKind GetKind() override { - return InstrumentKind::Counter; - } -}; + NoopUpDownSumObserver(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/, + void (*callback)(ObserverResult)) + {} + + virtual bool IsEnabled() override { return false; } + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual void observe(T value, const trace::KeyValueIterable &labels) override {} + + virtual void run() override {} + + virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } +}; template class BoundNoopCounter : public BoundCounter { - + public: - BoundNoopCounter() = default; - - BoundNoopCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - virtual void add(T value) override {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual InstrumentKind GetKind() override { - return InstrumentKind::Counter; - } - + BoundNoopCounter() = default; + + BoundNoopCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + virtual void add(T value) override {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } }; template class NoopCounter : public Counter { - + public: - NoopCounter() = default; - - NoopCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - nostd::shared_ptr> bindNoopCounter(const trace::KeyValueIterable & /*labels*/) - { - return nostd::shared_ptr>(new BoundNoopCounter()); - } - - virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual InstrumentKind GetKind() override { - return InstrumentKind::Counter; - } - + NoopCounter() = default; + + NoopCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + nostd::shared_ptr> bindNoopCounter(const trace::KeyValueIterable & /*labels*/) + { + return nostd::shared_ptr>(new BoundNoopCounter()); + } + + virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } }; template class BoundNoopUpDownCounter : public BoundUpDownCounter { - + public: - BoundNoopUpDownCounter() = default; - - BoundNoopUpDownCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - virtual void add(T value) override {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual InstrumentKind GetKind() override { - return InstrumentKind::UpDownCounter; - } - + BoundNoopUpDownCounter() = default; + + BoundNoopUpDownCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + virtual void add(T value) override {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual InstrumentKind GetKind() override { return InstrumentKind::UpDownCounter; } }; template class NoopUpDownCounter : public UpDownCounter { - + public: - NoopUpDownCounter() = default; - - NoopUpDownCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - nostd::shared_ptr> bindNoopUpDownCounter(const trace::KeyValueIterable & /*labels*/) - { - return nostd::shared_ptr>(new BoundNoopUpDownCounter()); - } - - virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual InstrumentKind GetKind() override { - return InstrumentKind::UpDownCounter; - } -}; + NoopUpDownCounter() = default; + + NoopUpDownCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + nostd::shared_ptr> bindNoopUpDownCounter( + const trace::KeyValueIterable & /*labels*/) + { + return nostd::shared_ptr>(new BoundNoopUpDownCounter()); + } + + virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual InstrumentKind GetKind() override { return InstrumentKind::UpDownCounter; } +}; template class BoundNoopValueRecorder : public BoundValueRecorder { - + public: - BoundNoopValueRecorder() = default; - - BoundNoopValueRecorder(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - virtual void record(T value) override {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual InstrumentKind GetKind() override { - return InstrumentKind::ValueRecorder; - } + BoundNoopValueRecorder() = default; + + BoundNoopValueRecorder(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + virtual void record(T value) override {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual InstrumentKind GetKind() override { return InstrumentKind::ValueRecorder; } }; template class NoopValueRecorder : public ValueRecorder { - + public: - NoopValueRecorder() = default; - - NoopValueRecorder(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - nostd::shared_ptr> bindNoopValueRecorder(const trace::KeyValueIterable & /*labels*/) - { - return nostd::shared_ptr>(new BoundNoopValueRecorder()); - } - - virtual void record(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual bool IsEnabled() override { - return false; - } - - virtual nostd::string_view GetName() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetDescription() override { - return nostd::string_view(""); - } - - virtual nostd::string_view GetUnits() override { - return nostd::string_view(""); - } - - virtual InstrumentKind GetKind() override { - return InstrumentKind::ValueRecorder; - } - -}; + NoopValueRecorder() = default; + NoopValueRecorder(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + nostd::shared_ptr> bindNoopValueRecorder( + const trace::KeyValueIterable & /*labels*/) + { + return nostd::shared_ptr>(new BoundNoopValueRecorder()); + } + + virtual void record(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual bool IsEnabled() override { return false; } + + virtual nostd::string_view GetName() override { return nostd::string_view(""); } + + virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } + + virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } + + virtual InstrumentKind GetKind() override { return InstrumentKind::ValueRecorder; } +}; -} // namespace metrics +} // namespace metrics OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/metrics/observer_result.h b/api/include/opentelemetry/metrics/observer_result.h index 5b675092eb..a16b5a3815 100644 --- a/api/include/opentelemetry/metrics/observer_result.h +++ b/api/include/opentelemetry/metrics/observer_result.h @@ -21,15 +21,15 @@ class ObserverResult public: ObserverResult() = default; - ObserverResult(AsynchronousInstrument * instrument): instrument_(instrument) {} + ObserverResult(AsynchronousInstrument *instrument) : instrument_(instrument) {} - virtual void observe(T value, const trace::KeyValueIterable &labels) { - instrument_->observe(value, labels); + virtual void observe(T value, const trace::KeyValueIterable &labels) + { + instrument_->observe(value, labels); } - -private: - AsynchronousInstrument * instrument_; +private: + AsynchronousInstrument *instrument_; }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/provider.h b/api/include/opentelemetry/metrics/provider.h index be79611e1e..8559562d8d 100644 --- a/api/include/opentelemetry/metrics/provider.h +++ b/api/include/opentelemetry/metrics/provider.h @@ -38,7 +38,7 @@ class Provider { while (GetLock().test_and_set(std::memory_order_acquire)) ; - GetProvider() = tp; + GetProvider() = tp; GetLock().clear(std::memory_order_release); } diff --git a/api/include/opentelemetry/metrics/sync_instruments.h b/api/include/opentelemetry/metrics/sync_instruments.h index 79f3a45097..8823d83e4d 100644 --- a/api/include/opentelemetry/metrics/sync_instruments.h +++ b/api/include/opentelemetry/metrics/sync_instruments.h @@ -9,163 +9,167 @@ namespace metrics template class BoundCounter : virtual public BoundSynchronousInstrument { - + public: - BoundCounter() = default; - - BoundCounter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /* - * Add adds the value to the counter's sum. The labels are already linked * to the instrument - * and are not specified. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value) = 0; + BoundCounter() = default; + + BoundCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /* + * Add adds the value to the counter's sum. The labels are already linked * to the instrument + * and are not specified. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value) = 0; }; template class Counter : virtual public SynchronousInstrument { - + public: - Counter() = default; - - Counter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled) {} - - /* - * Bind creates a bound instrument for this counter. The labels are - * associated with values recorded via subsequent calls to Record. - * - * @param labels the set of labels, as key-value pairs. - * @return a BoundIntCounter tied to the specified labels - */ - virtual nostd::shared_ptr> bindCounter(const trace::KeyValueIterable &labels) { - return nostd::shared_ptr>(); - } - - /* - * Add adds the value to the counter's sum. The labels should contain - * the keys and values to be associated with this value. Counters only * accept positive - * valued updates. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value, const trace::KeyValueIterable &labels) = 0; - - virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; + Counter() = default; + + Counter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled) + {} + + /* + * Bind creates a bound instrument for this counter. The labels are + * associated with values recorded via subsequent calls to Record. + * + * @param labels the set of labels, as key-value pairs. + * @return a BoundIntCounter tied to the specified labels + */ + virtual nostd::shared_ptr> bindCounter(const trace::KeyValueIterable &labels) + { + return nostd::shared_ptr>(); + } + + /* + * Add adds the value to the counter's sum. The labels should contain + * the keys and values to be associated with this value. Counters only * accept positive + * valued updates. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value, const trace::KeyValueIterable &labels) = 0; + + virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; }; template class BoundUpDownCounter : virtual public BoundSynchronousInstrument { - + public: - BoundUpDownCounter() = default; - - BoundUpDownCounter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /* - * Add adds the value to the counter's sum. The labels are already linked to * the instrument and - * do not need to specified again. UpDownCounters can accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value) = 0; + BoundUpDownCounter() = default; + + BoundUpDownCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /* + * Add adds the value to the counter's sum. The labels are already linked to * the instrument and + * do not need to specified again. UpDownCounters can accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value) = 0; }; template class UpDownCounter : virtual public SynchronousInstrument { - + public: - UpDownCounter() = default; - - UpDownCounter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - virtual nostd::shared_ptr> bindUpDownCounter(const trace::KeyValueIterable &labels) - { - return nostd::shared_ptr>(); - } - - /* - * Add adds the value to the counter's sum. The labels should contain - * the keys and values to be associated with this value. UpDownCounters can - * accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value, const trace::KeyValueIterable &labels) = 0; - - virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; + UpDownCounter() = default; + + UpDownCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + virtual nostd::shared_ptr> bindUpDownCounter( + const trace::KeyValueIterable &labels) + { + return nostd::shared_ptr>(); + } + + /* + * Add adds the value to the counter's sum. The labels should contain + * the keys and values to be associated with this value. UpDownCounters can + * accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value, const trace::KeyValueIterable &labels) = 0; + + virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; }; template class BoundValueRecorder : virtual public BoundSynchronousInstrument { - + public: - BoundValueRecorder() = default; - - BoundValueRecorder(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /* - * Records the value by summing it with previous measurements and checking * previously stored - * minimum and maximum values. The labels associated with * new values are already linked to the - * instrument as it is bound. * ValueRecorders can accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - */ - virtual void record(T value) = 0; -}; + BoundValueRecorder() = default; + + BoundValueRecorder(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + /* + * Records the value by summing it with previous measurements and checking * previously stored + * minimum and maximum values. The labels associated with * new values are already linked to the + * instrument as it is bound. * ValueRecorders can accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + */ + virtual void record(T value) = 0; +}; template class ValueRecorder : virtual public SynchronousInstrument { - + public: - ValueRecorder() = default; - - ValueRecorder(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - virtual nostd::shared_ptr> bindValueRecorder(const trace::KeyValueIterable &labels){ - return nostd::shared_ptr>(); - } - - /* - * Records the value by summing it with previous measurements and checking * previously stored - * minimum and maximum values. The labels should contain the keys and values to be associated with - * this value. ValueRecorders can accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void record(T value, const trace::KeyValueIterable &labels) = 0; - - virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; + ValueRecorder() = default; + + ValueRecorder(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + virtual nostd::shared_ptr> bindValueRecorder( + const trace::KeyValueIterable &labels) + { + return nostd::shared_ptr>(); + } + + /* + * Records the value by summing it with previous measurements and checking * previously stored + * minimum and maximum values. The labels should contain the keys and values to be associated with + * this value. ValueRecorders can accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void record(T value, const trace::KeyValueIterable &labels) = 0; + + virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; }; } // namespace metrics diff --git a/api/include/opentelemetry/nostd/string_view.h b/api/include/opentelemetry/nostd/string_view.h index e947d23259..315d038b3f 100644 --- a/api/include/opentelemetry/nostd/string_view.h +++ b/api/include/opentelemetry/nostd/string_view.h @@ -71,7 +71,7 @@ class string_view int compare(string_view v) const noexcept { size_type len = std::min(size(), v.size()); - int result = Traits::compare(data(), v.data(), len); + int result = Traits::compare(data(), v.data(), len); if (result == 0) result = size() == v.size() ? 0 : (size() < v.size() ? -1 : 1); return result; @@ -82,15 +82,16 @@ class string_view return substr(pos1, count1).compare(v); }; - int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const + int compare(size_type pos1, + size_type count1, + string_view v, + size_type pos2, + size_type count2) const { return substr(pos1, count1).compare(v.substr(pos2, count2)); }; - int compare(const char *s) const - { - return compare(string_view(s)); - }; + int compare(const char *s) const { return compare(string_view(s)); }; int compare(size_type pos1, size_type count1, const char *s) const { @@ -102,15 +103,9 @@ class string_view return substr(pos1, count1).compare(string_view(s, count2)); }; - bool operator<(const string_view v) const noexcept - { - return compare(v) < 0; - } + bool operator<(const string_view v) const noexcept { return compare(v) < 0; } - bool operator>(const string_view v) const noexcept - { - return compare(v) > 0; - } + bool operator>(const string_view v) const noexcept { return compare(v) > 0; } private: // Note: uses the same binary layout as libstdc++'s std::string_view diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h index fc04ce17e6..57b6a72e2e 100644 --- a/api/include/opentelemetry/trace/span_context.h +++ b/api/include/opentelemetry/trace/span_context.h @@ -39,8 +39,9 @@ class SpanContext final * @param has_remote_parent a required parameter specifying if this context has * a remote parent */ - SpanContext(bool sampled_flag, bool has_remote_parent) : - trace_flags_(trace_api::TraceFlags((uint8_t) sampled_flag)), remote_parent_(has_remote_parent) {}; + SpanContext(bool sampled_flag, bool has_remote_parent) + : trace_flags_(trace_api::TraceFlags((uint8_t)sampled_flag)), + remote_parent_(has_remote_parent){}; // @returns the trace_flags associated with this span_context const trace_api::TraceFlags &trace_flags() const noexcept { return trace_flags_; } diff --git a/api/test/metrics/BUILD b/api/test/metrics/BUILD index 08cd98cf8e..a56dc3fcd0 100644 --- a/api/test/metrics/BUILD +++ b/api/test/metrics/BUILD @@ -21,4 +21,4 @@ cc_test( "//api", "@com_google_googletest//:gtest_main", ], -) \ No newline at end of file +) diff --git a/api/test/metrics/noop_instrument_test.cc b/api/test/metrics/noop_instrument_test.cc index 46f4babe42..5e53599f50 100644 --- a/api/test/metrics/noop_instrument_test.cc +++ b/api/test/metrics/noop_instrument_test.cc @@ -1,8 +1,8 @@ #include #include +#include #include #include "opentelemetry/metrics/noop.h" -#include OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics @@ -11,7 +11,7 @@ namespace metrics void noopIntCallback(ObserverResult result) { std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; result.observe(1, labelkv); result.observe(-1, labelkv); } @@ -19,7 +19,7 @@ void noopIntCallback(ObserverResult result) void noopDoubleCallback(ObserverResult result) { std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; result.observe(1.5, labelkv); result.observe(-1.5, labelkv); } @@ -31,7 +31,7 @@ TEST(ValueObserver, Observe) NoopValueObserver beta("test", "none", "unitless", true, &noopDoubleCallback); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.observe(1, labelkv); beta.observe(1.5, labelkv); @@ -44,7 +44,7 @@ TEST(SumObserver, DefaultConstruction) NoopSumObserver beta("test", "none", "unitless", true, &noopDoubleCallback); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.observe(1, labelkv); beta.observe(1.5, labelkv); @@ -57,7 +57,7 @@ TEST(UpDownSumObserver, DefaultConstruction) NoopUpDownSumObserver beta("test", "none", "unitless", true, &noopDoubleCallback); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.observe(1, labelkv); beta.observe(1.0, labelkv); @@ -71,7 +71,7 @@ TEST(Counter, DefaultConstruction) NoopCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.bind(labelkv); @@ -88,7 +88,7 @@ TEST(Counter, Add) NoopCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.add(1, labelkv); beta.add(1.5, labelkv); @@ -109,7 +109,7 @@ TEST(UpDownCounter, DefaultConstruction) NoopUpDownCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.bind(labelkv); @@ -126,7 +126,7 @@ TEST(UpDownCounter, Add) NoopUpDownCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.add(1, labelkv); beta.add(1.5, labelkv); @@ -149,7 +149,7 @@ TEST(ValueRecorder, DefaultConstruction) NoopValueRecorder beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.bind(labelkv); @@ -166,7 +166,7 @@ TEST(ValueRecorder, Record) NoopValueRecorder beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.record(1, labelkv); beta.record(1.5, labelkv); diff --git a/api/test/nostd/string_view_test.cc b/api/test/nostd/string_view_test.cc index 074d3bee49..364410a312 100644 --- a/api/test/nostd/string_view_test.cc +++ b/api/test/nostd/string_view_test.cc @@ -95,7 +95,7 @@ TEST(StringViewTest, Compare) TEST(StringViewTest, MapKeyOrdering) { std::map m = {{"bbb", 2}, {"aaa", 1}, {"ccc", 3}}; - size_t i = 1; + size_t i = 1; for (const auto &kv : m) { EXPECT_EQ(kv.second, i); diff --git a/api/test/trace/CMakeLists.txt b/api/test/trace/CMakeLists.txt index 3439146f7a..16cef9bc6d 100644 --- a/api/test/trace/CMakeLists.txt +++ b/api/test/trace/CMakeLists.txt @@ -1,5 +1,12 @@ -foreach(testname key_value_iterable_view_test noop_test provider_test - span_id_test trace_id_test trace_flags_test span_context_test) +foreach( + testname + key_value_iterable_view_test + noop_test + provider_test + span_id_test + trace_id_test + trace_flags_test + span_context_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/examples/simple/BUILD b/examples/simple/BUILD index df6ad8ecc7..a8e843e29d 100644 --- a/examples/simple/BUILD +++ b/examples/simple/BUILD @@ -18,8 +18,8 @@ cc_binary( ], deps = [ ":foo_library", - "//exporters/ostream:ostream_span_exporter", "//api", + "//exporters/ostream:ostream_span_exporter", "//sdk/src/trace", ], ) diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt index e69de29bb2..8b13789179 100644 --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/examples/simple/main.cc b/examples/simple/main.cc index 50cbc8fac7..485d31c2ec 100644 --- a/examples/simple/main.cc +++ b/examples/simple/main.cc @@ -3,17 +3,19 @@ #include "opentelemetry/trace/provider.h" // Using an exporter that simply dumps span data to stdout. -#include "opentelemetry/exporters/ostream/span_exporter.h" #include "foo_library/foo_library.h" +#include "opentelemetry/exporters/ostream/span_exporter.h" namespace { void initTracer() { - auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr( + new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); - auto provider = nostd::shared_ptr(new sdktrace::TracerProvider(processor)); + auto provider = nostd::shared_ptr( + new sdktrace::TracerProvider(processor)); // Set the global trace provider opentelemetry::trace::Provider::SetTracerProvider(provider); } diff --git a/exporters/ostream/CMakeLists.txt b/exporters/ostream/CMakeLists.txt index 54c93bc1aa..ebc595ed21 100644 --- a/exporters/ostream/CMakeLists.txt +++ b/exporters/ostream/CMakeLists.txt @@ -3,8 +3,8 @@ include_directories(include) add_library(opentelemetry_exporter_ostream_span src/span_exporter.cc) add_executable(ostream_span_test test/ostream_span_test.cc) -target_link_libraries(ostream_span_test - ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_ostream_span) -gtest_add_tests(TARGET ostream_span_test TEST_PREFIX exporter. TEST_LIST ostream_span_test) +target_link_libraries( + ostream_span_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_ostream_span) +gtest_add_tests(TARGET ostream_span_test TEST_PREFIX exporter. TEST_LIST + ostream_span_test) diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h index a4dd83a597..c20ba7d362 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h @@ -1,8 +1,8 @@ #pragma once +#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/span_data.h" -#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/version.h" #include @@ -20,16 +20,15 @@ namespace trace /** * The OStreamSpanExporter exports span data through an ostream -*/ + */ class OStreamSpanExporter final : public sdktrace::SpanExporter { public: - -/** - * Create an OStreamSpanExporter. This constructor takes in a reference to an ostream that the - * export() function will send span data into. - * The default ostream is set to stdout - */ + /** + * Create an OStreamSpanExporter. This constructor takes in a reference to an ostream that the + * export() function will send span data into. + * The default ostream is set to stdout + */ explicit OStreamSpanExporter(std::ostream &sout = std::cout) noexcept; std::unique_ptr MakeRecordable() noexcept override; @@ -44,29 +43,28 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter bool isShutdown_ = false; // Mapping status number to the string from api/include/opentelemetry/trace/canonical_code.h - std::map statusMap { - {0, "OK"}, - {1, "CANCELLED"}, - {2, "UNKNOWN"}, - {3, "INVALID_ARGUMENT"}, - {4, "DEADLINE_EXCEEDED"}, - {5, "NOT_FOUND"}, - {6, "ALREADY_EXISTS"}, - {7, "PERMISSION_DENIED"}, - {8, "RESOURCE_EXHAUSTED"}, - {9, "FAILED_PRECONDITION"}, - {10, "ABORTED"}, - {11, "OUT_OF_RANGE"}, - {12, "UNIMPLEMENTED"}, - {13, "INTERNAL"}, - {14, "UNAVAILABLE"}, - {15, "DATA_LOSS"}, - {16, "UNAUTHENTICATED"} - }; + std::map statusMap{{0, "OK"}, + {1, "CANCELLED"}, + {2, "UNKNOWN"}, + {3, "INVALID_ARGUMENT"}, + {4, "DEADLINE_EXCEEDED"}, + {5, "NOT_FOUND"}, + {6, "ALREADY_EXISTS"}, + {7, "PERMISSION_DENIED"}, + {8, "RESOURCE_EXHAUSTED"}, + {9, "FAILED_PRECONDITION"}, + {10, "ABORTED"}, + {11, "OUT_OF_RANGE"}, + {12, "UNIMPLEMENTED"}, + {13, "INTERNAL"}, + {14, "UNAVAILABLE"}, + {15, "DATA_LOSS"}, + {16, "UNAUTHENTICATED"}}; /* - print_array and print_value are used to print out the value of an attribute within a vector. These values - are held in a variant which makes the process of printing them much more complicated. + print_array and print_value are used to print out the value of an attribute within a vector. + These values are held in a variant which makes the process of printing them much more + complicated. */ template @@ -78,7 +76,7 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter size_t sz = s.size(); for (auto v : s) { - sout_ << v; + sout_ << v; if (i != sz) sout_ << ','; i++; @@ -88,43 +86,43 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter void print_value(sdktrace::SpanDataAttributeValue &value) { - if(nostd::holds_alternative(value)) + if (nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if(nostd::holds_alternative(value)) + else if (nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if(nostd::holds_alternative(value)) + else if (nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if(nostd::holds_alternative(value)) + else if (nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if(nostd::holds_alternative(value)) + else if (nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if(nostd::holds_alternative>(value)) + else if (nostd::holds_alternative>(value)) { print_array(value); } - else if(nostd::holds_alternative>(value)) + else if (nostd::holds_alternative>(value)) { print_array(value); } - else if(nostd::holds_alternative>(value)) + else if (nostd::holds_alternative>(value)) { print_array(value); } - else if(nostd::holds_alternative>(value)) + else if (nostd::holds_alternative>(value)) { print_array(value); } - else if(nostd::holds_alternative>(value)) + else if (nostd::holds_alternative>(value)) { print_array(value); } @@ -133,8 +131,8 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter void printAttributes(std::unordered_map map) { int size = map.size(); - int i = 1; - for(auto kv : map) + int i = 1; + for (auto kv : map) { sout_ << kv.first << ": "; print_value(kv.second); @@ -143,10 +141,8 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter sout_ << ", "; i++; } - } - }; -} -} +} // namespace trace +} // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/ostream/src/span_exporter.cc b/exporters/ostream/src/span_exporter.cc index 7e2e4237ab..3837d7110b 100644 --- a/exporters/ostream/src/span_exporter.cc +++ b/exporters/ostream/src/span_exporter.cc @@ -10,61 +10,60 @@ namespace exporter { namespace trace { -OStreamSpanExporter::OStreamSpanExporter(std::ostream &sout) noexcept - : sout_(sout) {} +OStreamSpanExporter::OStreamSpanExporter(std::ostream &sout) noexcept : sout_(sout) {} -std::unique_ptr OStreamSpanExporter::MakeRecordable() noexcept +std::unique_ptr OStreamSpanExporter::MakeRecordable() noexcept { - return std::unique_ptr(new sdktrace::SpanData); + return std::unique_ptr(new sdktrace::SpanData); } sdktrace::ExportResult OStreamSpanExporter::Export( const nostd::span> &spans) noexcept { - if(isShutdown_) - { - return sdktrace::ExportResult::kFailure; - } + if (isShutdown_) + { + return sdktrace::ExportResult::kFailure; + } - for (auto &recordable : spans) - { - auto span = std::unique_ptr( - static_cast(recordable.release())); + for (auto &recordable : spans) + { + auto span = std::unique_ptr( + static_cast(recordable.release())); - if (span != nullptr) - { + if (span != nullptr) + { - char trace_id[32] = {0}; - char span_id[16] = {0}; - char parent_span_id[16] = {0}; + char trace_id[32] = {0}; + char span_id[16] = {0}; + char parent_span_id[16] = {0}; - span->GetTraceId().ToLowerBase16(trace_id); - span->GetSpanId().ToLowerBase16(span_id); - span->GetParentSpanId().ToLowerBase16(parent_span_id); + span->GetTraceId().ToLowerBase16(trace_id); + span->GetSpanId().ToLowerBase16(span_id); + span->GetParentSpanId().ToLowerBase16(parent_span_id); - sout_ << "{" - << "\n name : " << span->GetName() - << "\n trace_id : " << std::string(trace_id, 32) - << "\n span_id : " << std::string(span_id, 16) - << "\n parent_span_id: " << std::string(parent_span_id, 16) - << "\n start : " << span->GetStartTime().time_since_epoch().count() - << "\n duration : " << span->GetDuration().count() - << "\n description : " << span->GetDescription() - << "\n status : " << statusMap[int(span->GetStatus())] - << "\n attributes : "; - printAttributes(span->GetAttributes()); - sout_ << "\n}\n"; - } + sout_ << "{" + << "\n name : " << span->GetName() + << "\n trace_id : " << std::string(trace_id, 32) + << "\n span_id : " << std::string(span_id, 16) + << "\n parent_span_id: " << std::string(parent_span_id, 16) + << "\n start : " << span->GetStartTime().time_since_epoch().count() + << "\n duration : " << span->GetDuration().count() + << "\n description : " << span->GetDescription() + << "\n status : " << statusMap[int(span->GetStatus())] + << "\n attributes : "; + printAttributes(span->GetAttributes()); + sout_ << "\n}\n"; } + } - return sdktrace::ExportResult::kSuccess; + return sdktrace::ExportResult::kSuccess; } -void OStreamSpanExporter::Shutdown(std::chrono::microseconds timeout) noexcept +void OStreamSpanExporter::Shutdown(std::chrono::microseconds timeout) noexcept { isShutdown_ = true; } -} // namespace trace -} // namespace exporter +} // namespace trace +} // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/ostream/test/ostream_span_test.cc b/exporters/ostream/test/ostream_span_test.cc index 5bc0697b56..e1f0c6b937 100644 --- a/exporters/ostream/test/ostream_span_test.cc +++ b/exporters/ostream/test/ostream_span_test.cc @@ -1,14 +1,13 @@ +#include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/span_data.h" #include "opentelemetry/sdk/trace/tracer_provider.h" #include "opentelemetry/trace/provider.h" -#include "opentelemetry/sdk/trace/span_data.h" -#include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/exporters/ostream/span_exporter.h" - #include #include @@ -20,7 +19,8 @@ namespace sdktrace = opentelemetry::sdk::trace; // Testing Shutdown functionality of OStreamSpanExporter, should expect no data to be sent to Stream TEST(OStreamSpanExporter, Shutdown) { - auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr( + new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); @@ -41,19 +41,20 @@ TEST(OStreamSpanExporter, Shutdown) std::cout.rdbuf(sbuf); - ASSERT_EQ(stdoutOutput.str(),""); + ASSERT_EQ(stdoutOutput.str(), ""); } // Testing what a default span that is not changed will print out, either all 0's or empty values TEST(OStreamSpanExporter, PrintDefaultSpan) { - auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr( + new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto recordable = processor->MakeRecordable(); - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -74,24 +75,25 @@ TEST(OStreamSpanExporter, PrintDefaultSpan) std::cout.rdbuf(sbuf); std::string expectedOutput = - "{\n" - " name : \n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : 0\n" - " duration : 0\n" - " description : \n" - " status : OK\n" - " attributes : \n" - "}\n"; - ASSERT_EQ(stdoutOutput.str(),expectedOutput); + "{\n" + " name : \n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " status : OK\n" + " attributes : \n" + "}\n"; + ASSERT_EQ(stdoutOutput.str(), expectedOutput); } // Testing if the changes we make to a span will carry over through the exporter TEST(OStreamSpanExporter, PrintChangedSpanCout) { - auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr( + new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); @@ -100,7 +102,7 @@ TEST(OStreamSpanExporter, PrintChangedSpanCout) recordable->SetName("Test Span"); opentelemetry::core::SystemTimestamp now(std::chrono::system_clock::now()); - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -109,7 +111,7 @@ TEST(OStreamSpanExporter, PrintChangedSpanCout) recordable->SetStartTime(now); recordable->SetDuration(std::chrono::nanoseconds(100)); - recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED,"Test Description"); + recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED, "Test Description"); recordable->SetAttribute("attr1", "string"); @@ -129,32 +131,35 @@ TEST(OStreamSpanExporter, PrintChangedSpanCout) std::string start = std::to_string(now.time_since_epoch().count()); std::string expectedOutput = - "{\n" - " name : Test Span\n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : " + start + "\n" - " duration : 100\n" - " description : Test Description\n" - " status : UNIMPLEMENTED\n" - " attributes : attr1: string\n" - "}\n"; - ASSERT_EQ(stdoutOutput.str(),expectedOutput); + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : " + + start + + "\n" + " duration : 100\n" + " description : Test Description\n" + " status : UNIMPLEMENTED\n" + " attributes : attr1: string\n" + "}\n"; + ASSERT_EQ(stdoutOutput.str(), expectedOutput); } // PrintChangedSpan to std::cerr TEST(OStreamSpanExporter, PrintChangedSpanCerr) { - auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter(std::cerr)); + auto exporter = std::unique_ptr( + new opentelemetry::exporter::trace::OStreamSpanExporter(std::cerr)); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto recordable = processor->MakeRecordable(); recordable->SetName("Test Span"); - - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; + + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -165,10 +170,10 @@ TEST(OStreamSpanExporter, PrintChangedSpanCerr) recordable->SetStartTime(now); recordable->SetDuration(std::chrono::nanoseconds(100)); - recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED,"Test Description"); + recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED, "Test Description"); std::array array2 = {false, true, false}; - opentelemetry::nostd::span span2{array2.data(), array2.size()}; + opentelemetry::nostd::span span2{array2.data(), array2.size()}; recordable->SetAttribute("attr1", span2); // Create stringstream to redirect to @@ -187,24 +192,27 @@ TEST(OStreamSpanExporter, PrintChangedSpanCerr) std::string start = std::to_string(now.time_since_epoch().count()); std::string expectedOutput = - "{\n" - " name : Test Span\n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : " + start + "\n" - " duration : 100\n" - " description : Test Description\n" - " status : UNIMPLEMENTED\n" - " attributes : attr1: [0,1,0]\n" - "}\n"; - ASSERT_EQ(stdcerrOutput.str(),expectedOutput); + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : " + + start + + "\n" + " duration : 100\n" + " description : Test Description\n" + " status : UNIMPLEMENTED\n" + " attributes : attr1: [0,1,0]\n" + "}\n"; + ASSERT_EQ(stdcerrOutput.str(), expectedOutput); } // PrintChangedSpan to std::clog TEST(OStreamSpanExporter, PrintChangedSpanClog) { - auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter(std::clog)); + auto exporter = std::unique_ptr( + new opentelemetry::exporter::trace::OStreamSpanExporter(std::clog)); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); @@ -212,7 +220,7 @@ TEST(OStreamSpanExporter, PrintChangedSpanClog) recordable->SetName("Test Span"); - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -222,10 +230,10 @@ TEST(OStreamSpanExporter, PrintChangedSpanClog) recordable->SetStartTime(now); recordable->SetDuration(std::chrono::nanoseconds(100)); - recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED,"Test Description"); + recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED, "Test Description"); std::array array1 = {1, 2, 3}; - opentelemetry::nostd::span span1{array1.data(), array1.size()}; + opentelemetry::nostd::span span1{array1.data(), array1.size()}; recordable->SetAttribute("attr1", span1); // Create stringstream to redirect to @@ -244,16 +252,18 @@ TEST(OStreamSpanExporter, PrintChangedSpanClog) std::string start = std::to_string(now.time_since_epoch().count()); std::string expectedOutput = - "{\n" - " name : Test Span\n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : " + start + "\n" - " duration : 100\n" - " description : Test Description\n" - " status : UNIMPLEMENTED\n" - " attributes : attr1: [1,2,3]\n" - "}\n"; - ASSERT_EQ(stdclogOutput.str(),expectedOutput); + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : " + + start + + "\n" + " duration : 100\n" + " description : Test Description\n" + " status : UNIMPLEMENTED\n" + " attributes : attr1: [1,2,3]\n" + "}\n"; + ASSERT_EQ(stdclogOutput.str(), expectedOutput); } diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index fe15830e85..a10357a460 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -34,10 +34,10 @@ cc_library( cc_library( name = "otlp_exporter", srcs = [ - 'src/otlp_exporter.cc', + "src/otlp_exporter.cc", ], hdrs = [ - 'include/opentelemetry/exporters/otlp/otlp_exporter.h', + "include/opentelemetry/exporters/otlp/otlp_exporter.h", ], strip_include_prefix = "include", deps = [ @@ -60,7 +60,7 @@ cc_test( ) cc_test( - name = "otlp_exporter_test", + name = "otlp_exporter_test", srcs = ["test/otlp_exporter_test.cc"], deps = [ ":otlp_exporter", diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index cd99350d21..91a3d89337 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -5,9 +5,8 @@ target_link_libraries(opentelemetry_exporter_otprotocol $) add_executable(recordable_test test/recordable_test.cc) -target_link_libraries(recordable_test - ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_otprotocol - protobuf::libprotobuf) -gtest_add_tests(TARGET recordable_test TEST_PREFIX exporter. TEST_LIST recordable_test) +target_link_libraries( + recordable_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_otprotocol protobuf::libprotobuf) +gtest_add_tests(TARGET recordable_test TEST_PREFIX exporter. TEST_LIST + recordable_test) diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h index 4ac324f3ca..16a5252f0b 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h @@ -1,7 +1,7 @@ #pragma once -#include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h" +#include "opentelemetry/sdk/trace/exporter.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace exporter @@ -31,14 +31,15 @@ class OtlpExporter final : public opentelemetry::sdk::trace::SpanExporter * @param spans a span of unique pointers to span recordables */ sdk::trace::ExportResult Export( - const nostd::span> &spans) noexcept override; + const nostd::span> &spans) noexcept override; /** * Shut down the exporter. * @param timeout an optional timeout, the default timeout of 0 means that no * timeout is applied. */ - void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {}; + void Shutdown( + std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override{}; private: // For testing @@ -48,10 +49,10 @@ class OtlpExporter final : public opentelemetry::sdk::trace::SpanExporter std::unique_ptr trace_service_stub_; /** - * Create an OtlpExporter using the specified service stub. - * Only tests can call this constructor directly. - * @param stub the service stub to be used for exporting - */ + * Create an OtlpExporter using the specified service stub. + * Only tests can call this constructor directly. + * @param stub the service stub to be used for exporting + */ OtlpExporter(std::unique_ptr stub); }; } // namespace otlp diff --git a/exporters/otlp/test/otlp_exporter_benchmark.cc b/exporters/otlp/test/otlp_exporter_benchmark.cc index 191c7ab6a1..0accff0bf4 100644 --- a/exporters/otlp/test/otlp_exporter_benchmark.cc +++ b/exporters/otlp/test/otlp_exporter_benchmark.cc @@ -15,10 +15,10 @@ const int kNumIterations = 1000; const trace::TraceId kTraceId(std::array( {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})); -const trace::SpanId kSpanId(std::array( - {0, 0, 0, 0, 0, 0, 0, 2})); -const trace::SpanId kParentSpanId(std::array( - {0, 0, 0, 0, 0, 0, 0, 3})); +const trace::SpanId kSpanId(std::array({0, 0, 0, 0, 0, 0, 0, + 2})); +const trace::SpanId kParentSpanId(std::array({0, 0, 0, 0, 0, 0, + 0, 3})); // ----------------------- Helper classes and functions ------------------------ @@ -120,7 +120,7 @@ void BM_OtlpExporterEmptySpans(benchmark::State &state) std::unique_ptr testpeer(new OtlpExporterTestPeer()); auto exporter = testpeer->GetExporter(); - while(state.KeepRunningBatch(kNumIterations)) + while (state.KeepRunningBatch(kNumIterations)) { std::array, kBatchSize> recordables; CreateEmptySpans(recordables); @@ -135,7 +135,7 @@ void BM_OtlpExporterSparseSpans(benchmark::State &state) std::unique_ptr testpeer(new OtlpExporterTestPeer()); auto exporter = testpeer->GetExporter(); - while(state.KeepRunningBatch(kNumIterations)) + while (state.KeepRunningBatch(kNumIterations)) { std::array, kBatchSize> recordables; CreateSparseSpans(recordables); @@ -150,7 +150,7 @@ void BM_OtlpExporterDenseSpans(benchmark::State &state) std::unique_ptr testpeer(new OtlpExporterTestPeer()); auto exporter = testpeer->GetExporter(); - while(state.KeepRunningBatch(kNumIterations)) + while (state.KeepRunningBatch(kNumIterations)) { std::array, kBatchSize> recordables; CreateDenseSpans(recordables); diff --git a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h index a8f596696c..66a4c81dfb 100644 --- a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h +++ b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h @@ -8,9 +8,9 @@ #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/trace/recordable.h" +#include "opentelemetry/sdk/trace/span_data.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/span.h" -#include "opentelemetry/sdk/trace/span_data.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" @@ -20,19 +20,23 @@ using opentelemetry::sdk::trace::SpanDataEvent; namespace trace_api = opentelemetry::trace; OPENTELEMETRY_BEGIN_NAMESPACE -namespace ext { -namespace zpages { +namespace ext +{ +namespace zpages +{ /** * This class is a threadsafe version of span data used for zpages in OT */ -class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { - public: +class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable +{ +public: /** * Get the trace id for this span * @return the trace id for this span */ - opentelemetry::trace::TraceId GetTraceId() const noexcept { + opentelemetry::trace::TraceId GetTraceId() const noexcept + { std::lock_guard lock(mutex_); return trace_id_; } @@ -41,7 +45,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the span id for this span * @return the span id for this span */ - opentelemetry::trace::SpanId GetSpanId() const noexcept { + opentelemetry::trace::SpanId GetSpanId() const noexcept + { std::lock_guard lock(mutex_); return span_id_; } @@ -50,7 +55,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the parent span id for this span * @return the span id for this span's parent */ - opentelemetry::trace::SpanId GetParentSpanId() const noexcept { + opentelemetry::trace::SpanId GetParentSpanId() const noexcept + { std::lock_guard lock(mutex_); return parent_span_id_; } @@ -59,7 +65,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the name for this span * @return the name for this span */ - opentelemetry::nostd::string_view GetName() const noexcept { + opentelemetry::nostd::string_view GetName() const noexcept + { std::lock_guard lock(mutex_); return name_; } @@ -68,7 +75,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the status for this span * @return the status for this span */ - opentelemetry::trace::CanonicalCode GetStatus() const noexcept { + opentelemetry::trace::CanonicalCode GetStatus() const noexcept + { std::lock_guard lock(mutex_); return status_code_; } @@ -77,7 +85,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the status description for this span * @return the description of the the status of this span */ - opentelemetry::nostd::string_view GetDescription() const noexcept { + opentelemetry::nostd::string_view GetDescription() const noexcept + { std::lock_guard lock(mutex_); return status_desc_; } @@ -86,7 +95,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the start time for this span * @return the start time for this span */ - opentelemetry::core::SystemTimestamp GetStartTime() const noexcept { + opentelemetry::core::SystemTimestamp GetStartTime() const noexcept + { std::lock_guard lock(mutex_); return start_time_; } @@ -95,7 +105,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the duration for this span * @return the duration for this span */ - std::chrono::nanoseconds GetDuration() const noexcept { + std::chrono::nanoseconds GetDuration() const noexcept + { std::lock_guard lock(mutex_); return duration_; } @@ -104,50 +115,53 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { * Get the attributes for this span * @return the attributes for this span */ - const std::unordered_map GetAttributes() - const noexcept { + const std::unordered_map GetAttributes() const noexcept + { std::lock_guard lock(mutex_); return attributes_; } void SetIds(opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, - opentelemetry::trace::SpanId parent_span_id) noexcept override { + opentelemetry::trace::SpanId parent_span_id) noexcept override + { std::lock_guard lock(mutex_); - trace_id_ = trace_id; - span_id_ = span_id; + trace_id_ = trace_id; + span_id_ = span_id; parent_span_id_ = parent_span_id; } - void SetAttribute(nostd::string_view key, - const common::AttributeValue &value) noexcept override { + void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override + { std::lock_guard lock(mutex_); attributes_[std::string(key)] = nostd::visit(converter_, value); } - void SetStatus(trace_api::CanonicalCode code, - nostd::string_view description) noexcept override { + void SetStatus(trace_api::CanonicalCode code, nostd::string_view description) noexcept override + { std::lock_guard lock(mutex_); status_code_ = code; status_desc_ = std::string(description); } - void SetName(nostd::string_view name) noexcept override { + void SetName(nostd::string_view name) noexcept override + { std::lock_guard lock(mutex_); name_ = std::string(name); } - void SetStartTime( - opentelemetry::core::SystemTimestamp start_time) noexcept override { + void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override + { std::lock_guard lock(mutex_); start_time_ = start_time; } - void SetDuration(std::chrono::nanoseconds duration) noexcept override { + void SetDuration(std::chrono::nanoseconds duration) noexcept override + { std::lock_guard lock(mutex_); duration_ = duration; } - + void AddLink( opentelemetry::trace::SpanContext span_context, const trace_api::KeyValueIterable &attributes = @@ -157,7 +171,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { (void)span_context; (void)attributes; } - + void AddEvent( nostd::string_view name, core::SystemTimestamp timestamp = core::SystemTimestamp(std::chrono::system_clock::now()), @@ -169,7 +183,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { // TODO: handle attributes } - private: +private: mutable std::mutex mutex_; opentelemetry::trace::TraceId trace_id_; opentelemetry::trace::SpanId span_id_; @@ -177,8 +191,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { core::SystemTimestamp start_time_; std::chrono::nanoseconds duration_{0}; std::string name_; - opentelemetry::trace::CanonicalCode status_code_{ - opentelemetry::trace::CanonicalCode::OK}; + opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; std::unordered_map attributes_; std::vector events_; diff --git a/ext/include/opentelemetry/ext/zpages/tracez_processor.h b/ext/include/opentelemetry/ext/zpages/tracez_processor.h index aca13d72fa..926e430ead 100644 --- a/ext/include/opentelemetry/ext/zpages/tracez_processor.h +++ b/ext/include/opentelemetry/ext/zpages/tracez_processor.h @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/recordable.h" @@ -20,11 +20,12 @@ namespace zpages * The span processor passes and stores running and completed recordables (casted as span_data) * to be used by the TraceZ Data Aggregator. */ -class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor { - public: - - struct CollectedSpans { - std::unordered_set running; +class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor +{ +public: + struct CollectedSpans + { + std::unordered_set running; std::vector> completed; }; @@ -39,11 +40,13 @@ class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor { */ std::unique_ptr MakeRecordable() noexcept override { - return std::unique_ptr(new opentelemetry::sdk::trace::SpanData); + return std::unique_ptr( + new opentelemetry::sdk::trace::SpanData); } /* - * OnStart is called when a span starts; the recordable is cast to span_data and added to running_spans. + * OnStart is called when a span starts; the recordable is cast to span_data and added to + * running_spans. * @param span a recordable for a span that was just started */ void OnStart(opentelemetry::sdk::trace::Recordable &span) noexcept override; @@ -73,7 +76,8 @@ class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor { * timeout is applied. Currently, timeout does nothing. */ void ForceFlush( - std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {} + std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override + {} /* * Shut down the processor and do any cleanup required, which is none. @@ -82,9 +86,10 @@ class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor { * @param timeout an optional timeout, the default timeout of 0 means that no * timeout is applied. Currently, timeout does nothing. */ - void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {} + void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override + {} - private: +private: mutable std::mutex mtx_; CollectedSpans spans_; }; diff --git a/ext/src/zpages/BUILD b/ext/src/zpages/BUILD index 4b1a51df5c..a59d525897 100644 --- a/ext/src/zpages/BUILD +++ b/ext/src/zpages/BUILD @@ -21,7 +21,7 @@ cc_library( include_prefix = "ext/zpages", deps = [ "//api", - "//sdk:headers", "//ext:headers", + "//sdk:headers", ], ) diff --git a/ext/src/zpages/CMakeLists.txt b/ext/src/zpages/CMakeLists.txt index 7d912f195e..eeef261fba 100644 --- a/ext/src/zpages/CMakeLists.txt +++ b/ext/src/zpages/CMakeLists.txt @@ -1,8 +1,8 @@ -add_library(opentelemetry_zpages - tracez_processor.cc - ../../include/opentelemetry/ext/zpages/tracez_processor.h) +add_library( + opentelemetry_zpages + tracez_processor.cc ../../include/opentelemetry/ext/zpages/tracez_processor.h) target_include_directories(opentelemetry_zpages PUBLIC ../../include) -target_link_libraries(opentelemetry_zpages opentelemetry_api opentelemetry_trace) - +target_link_libraries(opentelemetry_zpages opentelemetry_api + opentelemetry_trace) diff --git a/ext/src/zpages/tracez_processor.cc b/ext/src/zpages/tracez_processor.cc index b76f49d72a..8e1dc5600d 100644 --- a/ext/src/zpages/tracez_processor.cc +++ b/ext/src/zpages/tracez_processor.cc @@ -1,37 +1,42 @@ #include "opentelemetry/ext/zpages/tracez_processor.h" OPENTELEMETRY_BEGIN_NAMESPACE -namespace ext { -namespace zpages { - - void TracezSpanProcessor::OnStart(opentelemetry::sdk::trace::Recordable &span) noexcept { - std::lock_guard lock(mtx_); - spans_.running.insert(static_cast(&span)); - } - - void TracezSpanProcessor::OnEnd(std::unique_ptr &&span) noexcept { - if (span == nullptr) return; - auto span_raw = static_cast(span.get()); - std::lock_guard lock(mtx_); - auto span_it = spans_.running.find(span_raw); - if (span_it != spans_.running.end()) { - spans_.running.erase(span_it); - spans_.completed.push_back( - std::unique_ptr( - static_cast(span.release()))); - } - } +namespace ext +{ +namespace zpages +{ +void TracezSpanProcessor::OnStart(opentelemetry::sdk::trace::Recordable &span) noexcept +{ + std::lock_guard lock(mtx_); + spans_.running.insert(static_cast(&span)); +} - TracezSpanProcessor::CollectedSpans TracezSpanProcessor::GetSpanSnapshot() noexcept { - CollectedSpans snapshot; - std::lock_guard lock(mtx_); - snapshot.running = spans_.running; - snapshot.completed = std::move(spans_.completed); - spans_.completed.clear(); - return snapshot; +void TracezSpanProcessor::OnEnd( + std::unique_ptr &&span) noexcept +{ + if (span == nullptr) + return; + auto span_raw = static_cast(span.get()); + std::lock_guard lock(mtx_); + auto span_it = spans_.running.find(span_raw); + if (span_it != spans_.running.end()) + { + spans_.running.erase(span_it); + spans_.completed.push_back(std::unique_ptr( + static_cast(span.release()))); } +} +TracezSpanProcessor::CollectedSpans TracezSpanProcessor::GetSpanSnapshot() noexcept +{ + CollectedSpans snapshot; + std::lock_guard lock(mtx_); + snapshot.running = spans_.running; + snapshot.completed = std::move(spans_.completed); + spans_.completed.clear(); + return snapshot; +} } // namespace zpages } // namespace ext diff --git a/ext/test/zpages/BUILD b/ext/test/zpages/BUILD index 3d6dfbc69a..1e71b420d9 100644 --- a/ext/test/zpages/BUILD +++ b/ext/test/zpages/BUILD @@ -4,8 +4,8 @@ cc_test( "threadsafe_span_data_test.cc", ], deps = [ - "//sdk/src/trace", "//ext/src/zpages", + "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], ) @@ -16,8 +16,8 @@ cc_test( "tracez_processor_test.cc", ], deps = [ - "//sdk/src/trace", "//ext/src/zpages", + "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], ) diff --git a/ext/test/zpages/CMakeLists.txt b/ext/test/zpages/CMakeLists.txt index 2fb33cde27..6f45e656d3 100644 --- a/ext/test/zpages/CMakeLists.txt +++ b/ext/test/zpages/CMakeLists.txt @@ -1,13 +1,7 @@ -foreach(testname - tracez_processor_test threadsafe_span_data_test) +foreach(testname tracez_processor_test threadsafe_span_data_test) add_executable(${testname} "${testname}.cc") - target_link_libraries( - ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_zpages) + target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_zpages) - gtest_add_tests( - TARGET ${testname} - TEST_PREFIX ext. - TEST_LIST ${testname}) + gtest_add_tests(TARGET ${testname} TEST_PREFIX ext. TEST_LIST ${testname}) endforeach() - diff --git a/ext/test/zpages/threadsafe_span_data_test.cc b/ext/test/zpages/threadsafe_span_data_test.cc index 51f6765eb0..4b0b6ce42a 100644 --- a/ext/test/zpages/threadsafe_span_data_test.cc +++ b/ext/test/zpages/threadsafe_span_data_test.cc @@ -6,9 +6,9 @@ #include #include +using opentelemetry::ext::zpages::ThreadsafeSpanData; using opentelemetry::sdk::trace::AttributeConverter; using opentelemetry::sdk::trace::SpanDataAttributeValue; -using opentelemetry::ext::zpages::ThreadsafeSpanData; TEST(ThreadsafeSpanData, DefaultValues) { diff --git a/ext/test/zpages/tracez_processor_test.cc b/ext/test/zpages/tracez_processor_test.cc index 53fa1dba6b..42a8736302 100644 --- a/ext/test/zpages/tracez_processor_test.cc +++ b/ext/test/zpages/tracez_processor_test.cc @@ -17,23 +17,26 @@ using namespace opentelemetry::ext::zpages; * Helper function uses the current processor to update spans contained in completed_spans * and running_spans. completed_spans contains all spans (cumulative), unless marked otherwise */ -void UpdateSpans(std::shared_ptr& processor, - std::vector>& completed, - std::unordered_set& running, - bool store_only_new_completed = false) { +void UpdateSpans(std::shared_ptr &processor, + std::vector> &completed, + std::unordered_set &running, + bool store_only_new_completed = false) +{ auto spans = processor->GetSpanSnapshot(); - running = spans.running; - if (store_only_new_completed) { + running = spans.running; + if (store_only_new_completed) + { completed.clear(); completed = std::move(spans.completed); - } else { + } + else + { std::move(spans.completed.begin(), spans.completed.end(), - std::inserter(completed, completed.end())); + std::inserter(completed, completed.end())); } spans.completed.clear(); } - /* * Returns true if all the span names in the name vector within the given range appears in * at least the same frequency as they do in running_spans. @@ -43,37 +46,45 @@ void UpdateSpans(std::shared_ptr& processor, * If 1-1 correspondance marked, return true if completed has all names in same frequency, * no more or less */ -bool ContainsNames(const std::vector& names, - std::unordered_set& running, - unsigned int name_start = 0, unsigned int name_end = 0, - bool one_to_one_correspondence = false) { - if (name_end == 0) name_end = names.size(); +bool ContainsNames(const std::vector &names, + std::unordered_set &running, + unsigned int name_start = 0, + unsigned int name_end = 0, + bool one_to_one_correspondence = false) +{ + if (name_end == 0) + name_end = names.size(); unsigned int num_names = name_end - name_start; - if (num_names > running.size() || // More names than spans, can't have all names - (one_to_one_correspondence && num_names != running.size())) { + if (num_names > running.size() || // More names than spans, can't have all names + (one_to_one_correspondence && num_names != running.size())) + { return false; } std::vector is_contained(num_names, false); // Mark all names that are contained only once // in the order they appear - for (auto &span : running) { - for (unsigned int i = 0; i < num_names; i++) { - if (span->GetName() == names[name_start + i] && !is_contained[i]) { + for (auto &span : running) + { + for (unsigned int i = 0; i < num_names; i++) + { + if (span->GetName() == names[name_start + i] && !is_contained[i]) + { is_contained[i] = true; break; } } } - for (auto &&b : is_contained) if (!b) return false; + for (auto &&b : is_contained) + if (!b) + return false; return true; } - /* * Returns true if all the span names in the nam vector within the given range appears in * at least the same frequency as they do in completed_spans @@ -83,114 +94,126 @@ bool ContainsNames(const std::vector& names, * If 1-1 correspondance marked, return true if completed has all names in same frequency, * no more or less */ -bool ContainsNames(const std::vector& names, - std::vector>& completed, - unsigned int name_start = 0, unsigned int name_end = 0, - bool one_to_one_correspondence = false) { +bool ContainsNames(const std::vector &names, + std::vector> &completed, + unsigned int name_start = 0, + unsigned int name_end = 0, + bool one_to_one_correspondence = false) +{ - if (name_end == 0) name_end = names.size(); + if (name_end == 0) + name_end = names.size(); unsigned int num_names = name_end - name_start; - if (num_names > completed.size() || - (one_to_one_correspondence && num_names != completed.size())) { - return false; + if (num_names > completed.size() || (one_to_one_correspondence && num_names != completed.size())) + { + return false; } std::vector is_contained(num_names, false); - for (auto &span : completed) { - for (unsigned int i = 0; i < num_names; i++) { - if (span->GetName() == names[name_start + i] && !is_contained[i]) { + for (auto &span : completed) + { + for (unsigned int i = 0; i < num_names; i++) + { + if (span->GetName() == names[name_start + i] && !is_contained[i]) + { is_contained[i] = true; break; } } } - for (auto &&b : is_contained) if (!b) return false; + for (auto &&b : is_contained) + if (!b) + return false; return true; } - /* * Helper function calls GetSpanSnapshot() i times and does nothing with it * otherwise. Used for testing thread safety */ -void GetManySnapshots(std::shared_ptr& processor, int i) { - for (; i > 0; i--) processor->GetSpanSnapshot(); +void GetManySnapshots(std::shared_ptr &processor, int i) +{ + for (; i > 0; i--) + processor->GetSpanSnapshot(); } - /* * Helper function that creates i spans, which are added into the passed * in vector. Used for testing thread safety */ -void StartManySpans(std::vector> &spans, - std::shared_ptr tracer, int i) { - for (; i > 0; i--) spans.push_back(tracer->StartSpan("span")); +void StartManySpans( + std::vector> &spans, + std::shared_ptr tracer, + int i) +{ + for (; i > 0; i--) + spans.push_back(tracer->StartSpan("span")); } - /* * Helper function that ends all spans in the passed in span vector. Used * for testing thread safety */ -void EndAllSpans(std::vector> &spans) { - for (auto &span : spans) span->End(); +void EndAllSpans(std::vector> &spans) +{ + for (auto &span : spans) + span->End(); } - //////////////////////////////// TEST FIXTURE ////////////////////////////////////// /* * Reduce code duplication by having single area with shared setup code */ -class TracezProcessor : public ::testing::Test { - protected: - void SetUp() override { - processor = std::shared_ptr(new TracezSpanProcessor()); - tracer = std::shared_ptr(new Tracer(processor)); +class TracezProcessor : public ::testing::Test +{ +protected: + void SetUp() override + { + processor = std::shared_ptr(new TracezSpanProcessor()); + tracer = std::shared_ptr(new Tracer(processor)); auto spans = processor->GetSpanSnapshot(); - running = spans.running; - completed = std::move(spans.completed); + running = spans.running; + completed = std::move(spans.completed); span_names = {"s0", "s2", "s1", "s1", "s"}; - } std::shared_ptr processor; std::shared_ptr tracer; - std::unordered_set running; + std::unordered_set running; std::vector> completed; std::vector span_names; std::vector> span_vars; - }; - ///////////////////////////////////////// TESTS /////////////////////////////////// /* * Test if both span containers are empty when no spans exist or are added. * Ensures no rogue spans appear in the containers somehow. */ -TEST_F(TracezProcessor, NoSpans) { +TEST_F(TracezProcessor, NoSpans) +{ auto recordable = processor->MakeRecordable(); EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 0); } - /* * Test if a single span moves from running to completed at expected times. * All completed spans are stored. Ensures basic functionality and that accumulation * can happen -*/ -TEST_F(TracezProcessor, OneSpanCumulative) { + */ +TEST_F(TracezProcessor, OneSpanCumulative) +{ auto span = tracer->StartSpan(span_names[0]); UpdateSpans(processor, completed, running); @@ -206,46 +229,49 @@ TEST_F(TracezProcessor, OneSpanCumulative) { EXPECT_EQ(completed.size(), 1); } - /* * Test if multiple spans move from running to completed at expected times. Check if * all are in a container, either running/completed during checks. Ensures basic functionality * and that accumulation can happen for many spans * All completed spans are stored. -*/ -TEST_F(TracezProcessor, MultipleSpansCumulative) { + */ +TEST_F(TracezProcessor, MultipleSpansCumulative) +{ EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 0); // Start and store spans using span_names - for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); + for (const auto &name : span_names) + span_vars.push_back(tracer->StartSpan(name)); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), span_names.size()); EXPECT_EQ(completed.size(), 0); // End all spans - for (auto &span : span_vars) span->End(); + for (auto &span : span_vars) + span->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), span_names.size()); } - /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Middle spans end first. Ensures basic functionality * and that accumulation can happen for many spans even spans that start and end non- * sequentially. All completed spans are stored. -*/ -TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) { - for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); + */ +TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) +{ + for (const auto &name : span_names) + span_vars.push_back(tracer->StartSpan(name)); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), span_names.size()); EXPECT_EQ(completed.size(), 0); @@ -253,9 +279,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) { span_vars[3]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -263,11 +289,11 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) { span_vars[1]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, running, 2, 3)); // + s1 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 2)); // s2 - EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 2, 3)); // + s1 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 2)); // s2 + EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 EXPECT_EQ(running.size(), 3); EXPECT_EQ(completed.size(), 2); @@ -275,9 +301,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) { span_vars[2]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4)); // s2 s1 s1 EXPECT_EQ(running.size(), 2); EXPECT_EQ(completed.size(), 3); @@ -286,27 +312,28 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) { span_vars[4]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 5); } - /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Ensures basic functionality and that * accumulation can happen for many spans even spans that start and end non- * sequentially. All completed spans are stored. -*/ -TEST_F(TracezProcessor, MultipleSpansOuterSplitCumulative) { - for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); + */ +TEST_F(TracezProcessor, MultipleSpansOuterSplitCumulative) +{ + for (const auto &name : span_names) + span_vars.push_back(tracer->StartSpan(name)); // End last span span_vars[4]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 4)); // s0 s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s + EXPECT_TRUE(ContainsNames(span_names, running, 0, 4)); // s0 s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -314,28 +341,29 @@ TEST_F(TracezProcessor, MultipleSpansOuterSplitCumulative) { span_vars[0]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 1, 4)); // s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s + EXPECT_TRUE(ContainsNames(span_names, running, 1, 4)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s EXPECT_EQ(running.size(), 3); EXPECT_EQ(completed.size(), 2); // End remaining Spans - for (int i = 1; i < 4; i++) span_vars[i]->End(); + for (int i = 1; i < 4; i++) + span_vars[i]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 5); } - /* * Test if a single span moves from running to completed at expected times. * Ensure correct behavior even when spans are discarded. Only new completed * spans are stored. -*/ -TEST_F(TracezProcessor, OneSpanNewOnly) { + */ +TEST_F(TracezProcessor, OneSpanNewOnly) +{ auto span = tracer->StartSpan(span_names[0]); UpdateSpans(processor, completed, running, true); @@ -356,18 +384,19 @@ TEST_F(TracezProcessor, OneSpanNewOnly) { EXPECT_EQ(completed.size(), 0); } - /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Middle spans end first. Ensure correct * behavior even when multiple spans are discarded, even when span starting and * ending is non-sequential. Only new completed spans are stored. */ -TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) { - for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); +TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) +{ + for (const auto &name : span_names) + span_vars.push_back(tracer->StartSpan(name)); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 5, true)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, running, 0, 5, true)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), span_names.size()); EXPECT_EQ(completed.size(), 0); @@ -375,9 +404,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) { span_vars[3]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4, true)); // s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4, true)); // s1 EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -386,9 +415,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) { span_vars[2]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 3, true)); // s2 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 3, true)); // s2 s1 EXPECT_EQ(running.size(), 2); EXPECT_EQ(completed.size(), 2); @@ -397,8 +426,8 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) { span_vars[4]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s + EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 2); @@ -408,22 +437,23 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) { EXPECT_EQ(completed.size(), 0); } - /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Ensure correct behavior even when * multiple spans are discarded, even when span starting and ending is * non-sequential. Only new completed spans are stored. -*/ -TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) { - for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); + */ +TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) +{ + for (const auto &name : span_names) + span_vars.push_back(tracer->StartSpan(name)); // End last span span_vars[4]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 4, true)); // s0 s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 4, 5, true)); // s + EXPECT_TRUE(ContainsNames(span_names, running, 0, 4, true)); // s0 s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 4, 5, true)); // s EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -431,16 +461,17 @@ TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) { span_vars[0]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 1, 4, true)); // s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1, true)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 1, 4, true)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1, true)); // s0 EXPECT_EQ(running.size(), 3); EXPECT_EQ(completed.size(), 1); // End remaining middle spans - for (int i = 1; i < 4; i++) span_vars[i]->End(); + for (int i = 1; i < 4; i++) + span_vars[i]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4, true)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4, true)); // s2 s1 s1 EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 3); @@ -450,12 +481,12 @@ TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) { EXPECT_EQ(completed.size(), 0); } - /* * Test for ForceFlush and Shutdown code coverage, which do nothing. */ -TEST_F(TracezProcessor, FlushShutdown) { - auto pre_running_sz = running.size(); +TEST_F(TracezProcessor, FlushShutdown) +{ + auto pre_running_sz = running.size(); auto pre_completed_sz = completed.size(); processor->ForceFlush(); @@ -467,11 +498,11 @@ TEST_F(TracezProcessor, FlushShutdown) { EXPECT_EQ(pre_completed_sz, completed.size()); } - /* * Test for thread safety when many spans start at the same time. */ -TEST_F(TracezProcessor, RunningThreadSafety) { +TEST_F(TracezProcessor, RunningThreadSafety) +{ std::vector> spans1; std::vector> spans2; @@ -482,11 +513,11 @@ TEST_F(TracezProcessor, RunningThreadSafety) { start2.join(); } - /* * Test for thread safety when many spans end at the same time */ -TEST_F(TracezProcessor, CompletedThreadSafety) { +TEST_F(TracezProcessor, CompletedThreadSafety) +{ std::vector> spans1; std::vector> spans2; StartManySpans(spans1, tracer, 500); @@ -499,11 +530,11 @@ TEST_F(TracezProcessor, CompletedThreadSafety) { end2.join(); } - /* * Test for thread safety when many snapshots are grabbed at the same time. */ -TEST_F(TracezProcessor, SnapshotThreadSafety) { +TEST_F(TracezProcessor, SnapshotThreadSafety) +{ std::vector> spans; std::thread snap1(GetManySnapshots, std::ref(processor), 500); @@ -521,11 +552,11 @@ TEST_F(TracezProcessor, SnapshotThreadSafety) { snap4.join(); } - /* * Test for thread safety when many spans start while others are ending. */ -TEST_F(TracezProcessor, RunningCompletedThreadSafety) { +TEST_F(TracezProcessor, RunningCompletedThreadSafety) +{ std::vector> spans1; std::vector> spans2; StartManySpans(spans1, tracer, 500); @@ -537,11 +568,11 @@ TEST_F(TracezProcessor, RunningCompletedThreadSafety) { end.join(); } - /* * Test for thread safety when many span start while snapshots are being grabbed. */ -TEST_F(TracezProcessor, RunningSnapshotThreadSafety) { +TEST_F(TracezProcessor, RunningSnapshotThreadSafety) +{ std::vector> spans; std::thread start(StartManySpans, std::ref(spans), tracer, 500); @@ -551,11 +582,11 @@ TEST_F(TracezProcessor, RunningSnapshotThreadSafety) { snapshots.join(); } - /* * Test for thread safety when many spans end while snapshots are being grabbed. */ -TEST_F(TracezProcessor, SnapshotCompletedThreadSafety) { +TEST_F(TracezProcessor, SnapshotCompletedThreadSafety) +{ std::vector> spans; StartManySpans(spans, tracer, 500); @@ -566,11 +597,11 @@ TEST_F(TracezProcessor, SnapshotCompletedThreadSafety) { end.join(); } - /* * Test for thread safety when many spans start and end while snapshots are being grabbed. */ -TEST_F(TracezProcessor, RunningSnapshotCompletedThreadSafety) { +TEST_F(TracezProcessor, RunningSnapshotCompletedThreadSafety) +{ std::vector> spans1; std::vector> spans2; StartManySpans(spans1, tracer, 500); @@ -583,4 +614,3 @@ TEST_F(TracezProcessor, RunningSnapshotCompletedThreadSafety) { snapshots.join(); end.join(); } - diff --git a/sdk/include/opentelemetry/sdk/metrics/meter.h b/sdk/include/opentelemetry/sdk/metrics/meter.h index 2acbc76d3c..6b7dc1d370 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter.h @@ -13,8 +13,7 @@ namespace metrics class Meter final : public opentelemetry::metrics::Meter, public std::enable_shared_from_this { public: - }; -} // namespace trace +} // namespace metrics } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h index 7c3fbab4d8..4b5821c1b5 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -1,8 +1,8 @@ #pragma once +#include "opentelemetry/metrics/meter_provider.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/sdk/metrics/meter.h" -#include "opentelemetry/metrics/meter_provider.h" #include diff --git a/sdk/include/opentelemetry/sdk/trace/recordable.h b/sdk/include/opentelemetry/sdk/trace/recordable.h index dcf9a50c7a..68124db0e6 100644 --- a/sdk/include/opentelemetry/sdk/trace/recordable.h +++ b/sdk/include/opentelemetry/sdk/trace/recordable.h @@ -3,13 +3,13 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/sdk/common/empty_attributes.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/key_value_iterable.h" #include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/version.h" -#include "opentelemetry/sdk/common/empty_attributes.h" #include diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index f0ab885626..2308ae7080 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -2,9 +2,9 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/version.h" -#include "opentelemetry/trace/span_context.h" #include #include diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h index 5a11f1c10c..0137a6b181 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h @@ -18,11 +18,12 @@ class AlwaysOnSampler : public Sampler /** * @return Always return Decision RECORD_AND_SAMPLE */ - inline SamplingResult ShouldSample(const trace_api::SpanContext * /*parent_context*/, - trace_api::TraceId /*trace_id*/, - nostd::string_view /*name*/, - trace_api::SpanKind /*span_kind*/, - const trace_api::KeyValueIterable & /*attributes*/) noexcept override + inline SamplingResult ShouldSample( + const trace_api::SpanContext * /*parent_context*/, + trace_api::TraceId /*trace_id*/, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept override { return {Decision::RECORD_AND_SAMPLE, nullptr}; } diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h index 95cf9afa37..ce16f7e9c6 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h @@ -22,11 +22,11 @@ class ParentOrElseSampler : public Sampler * delegateSampler for root spans * @return Returns NOT_RECORD always */ - SamplingResult ShouldSample(const trace_api::SpanContext * parent_context, + SamplingResult ShouldSample(const trace_api::SpanContext *parent_context, trace_api::TraceId trace_id, nostd::string_view name, trace_api::SpanKind span_kind, - const trace_api::KeyValueIterable & attributes) noexcept override; + const trace_api::KeyValueIterable &attributes) noexcept override; /** * @return Description MUST be ParentOrElse{delegate_sampler_.getDescription()} diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/probability.h b/sdk/include/opentelemetry/sdk/trace/samplers/probability.h index aa585409a4..9ad8e7f0ea 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/probability.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/probability.h @@ -29,12 +29,11 @@ class ProbabilitySampler : public Sampler * is used as a pseudorandom value in conjunction with the predefined * threshold to determine whether this trace should be sampled */ - SamplingResult ShouldSample( - const trace_api::SpanContext *parent_context, - trace_api::TraceId trace_id, - nostd::string_view /*name*/, - trace_api::SpanKind /*span_kind*/, - const trace_api::KeyValueIterable & /*attributes*/) noexcept override; + SamplingResult ShouldSample(const trace_api::SpanContext *parent_context, + trace_api::TraceId trace_id, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept override; /** * @return Description MUST be ProbabilitySampler{0.000100} diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index c2b0d69e0c..e6f5547f2d 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -3,8 +3,8 @@ #include "opentelemetry/sdk/common/atomic_shared_ptr.h" #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" -#include "opentelemetry/trace/tracer.h" #include "opentelemetry/trace/noop.h" +#include "opentelemetry/trace/tracer.h" #include "opentelemetry/version.h" #include diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 97a0533e86..d003532a9b 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -5,9 +5,7 @@ namespace sdk { namespace metrics { -MeterProvider::MeterProvider() noexcept - : meter_(new Meter) -{} +MeterProvider::MeterProvider() noexcept : meter_(new Meter) {} opentelemetry::nostd::shared_ptr MeterProvider::GetMeter( nostd::string_view library_name, diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index 1e6d302461..d37699916e 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -1,2 +1,3 @@ -add_library(opentelemetry_trace tracer_provider.cc tracer.cc span.cc - samplers/parent_or_else.cc samplers/probability.cc) +add_library( + opentelemetry_trace tracer_provider.cc tracer.cc span.cc + samplers/parent_or_else.cc samplers/probability.cc) diff --git a/sdk/src/trace/samplers/parent_or_else.cc b/sdk/src/trace/samplers/parent_or_else.cc index f3b926c2b6..29026a0167 100644 --- a/sdk/src/trace/samplers/parent_or_else.cc +++ b/sdk/src/trace/samplers/parent_or_else.cc @@ -22,7 +22,7 @@ SamplingResult ParentOrElseSampler::ShouldSample( // If no parent (root span) exists returns the result of the delegateSampler return delegate_sampler_->ShouldSample(parent_context, trace_id, name, span_kind, attributes); } - + // If parent exists: if (parent_context->IsSampled()) { diff --git a/sdk/src/trace/samplers/probability.cc b/sdk/src/trace/samplers/probability.cc index 0038ed11fb..0fd45644e4 100644 --- a/sdk/src/trace/samplers/probability.cc +++ b/sdk/src/trace/samplers/probability.cc @@ -23,49 +23,50 @@ namespace trace_api = opentelemetry::trace; namespace { - /** - * Converts a probability in [0, 1] to a threshold in [0, UINT64_MAX] - * - * @param probability a required value top be converted to uint64_t. is - * bounded by 1 >= probability >= 0. - * @return Returns threshold value computed after converting probability to - * uint64_t datatype - */ - uint64_t CalculateThreshold(double probability) noexcept - { - if (probability <= 0.0) return 0; - if (probability >= 1.0) return UINT64_MAX; - - // We can't directly return probability * UINT64_MAX. - // - // UINT64_MAX is (2^64)-1, but as a double rounds up to 2^64. - // For probabilities >= 1-(2^-54), the product wraps to zero! - // Instead, calculate the high and low 32 bits separately. - const double product = UINT32_MAX * probability; - double hi_bits, lo_bits = ldexp(modf(product, &hi_bits), 32) + product; - return (static_cast(hi_bits) << 32) + - static_cast(lo_bits); - } +/** + * Converts a probability in [0, 1] to a threshold in [0, UINT64_MAX] + * + * @param probability a required value top be converted to uint64_t. is + * bounded by 1 >= probability >= 0. + * @return Returns threshold value computed after converting probability to + * uint64_t datatype + */ +uint64_t CalculateThreshold(double probability) noexcept +{ + if (probability <= 0.0) + return 0; + if (probability >= 1.0) + return UINT64_MAX; - /** - * @param trace_id a required value to be converted to uint64_t. trace_id must - * at least 8 bytes long - * @return Returns threshold value computed after converting trace_id to - * uint64_t datatype - */ - uint64_t CalculateThresholdFromBuffer(const trace_api::TraceId& trace_id) noexcept - { - // We only use the first 8 bytes of TraceId. - static_assert(trace_api::TraceId::kSize >= 8, "TraceID must be at least 8 bytes long."); + // We can't directly return probability * UINT64_MAX. + // + // UINT64_MAX is (2^64)-1, but as a double rounds up to 2^64. + // For probabilities >= 1-(2^-54), the product wraps to zero! + // Instead, calculate the high and low 32 bits separately. + const double product = UINT32_MAX * probability; + double hi_bits, lo_bits = ldexp(modf(product, &hi_bits), 32) + product; + return (static_cast(hi_bits) << 32) + static_cast(lo_bits); +} - uint64_t res = 0; - std::memcpy(&res, &trace_id, 8); +/** + * @param trace_id a required value to be converted to uint64_t. trace_id must + * at least 8 bytes long + * @return Returns threshold value computed after converting trace_id to + * uint64_t datatype + */ +uint64_t CalculateThresholdFromBuffer(const trace_api::TraceId &trace_id) noexcept +{ + // We only use the first 8 bytes of TraceId. + static_assert(trace_api::TraceId::kSize >= 8, "TraceID must be at least 8 bytes long."); - double probability = (double) res / UINT64_MAX; + uint64_t res = 0; + std::memcpy(&res, &trace_id, 8); - return CalculateThreshold(probability); - } -} // namespace + double probability = (double)res / UINT64_MAX; + + return CalculateThreshold(probability); +} +} // namespace OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -73,36 +74,43 @@ namespace sdk namespace trace { ProbabilitySampler::ProbabilitySampler(double probability) -: threshold_(CalculateThreshold(probability)) + : threshold_(CalculateThreshold(probability)) { - if (probability > 1.0) probability = 1.0; - if (probability < 0.0) probability = 0.0; - description_ = "ProbabilitySampler{" + std::to_string(probability) + "}"; - } + if (probability > 1.0) + probability = 1.0; + if (probability < 0.0) + probability = 0.0; + description_ = "ProbabilitySampler{" + std::to_string(probability) + "}"; +} SamplingResult ProbabilitySampler::ShouldSample( - const trace_api::SpanContext *parent_context, - trace_api::TraceId trace_id, - nostd::string_view /*name*/, - trace_api::SpanKind /*span_kind*/, - const trace_api::KeyValueIterable & /*attributes*/) noexcept + const trace_api::SpanContext *parent_context, + trace_api::TraceId trace_id, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept { - if (parent_context && !parent_context->HasRemoteParent()) { - if (parent_context->IsSampled()) { - return { Decision::RECORD_AND_SAMPLE, nullptr }; - } else { - return { Decision::NOT_RECORD, nullptr }; + if (parent_context && !parent_context->HasRemoteParent()) + { + if (parent_context->IsSampled()) + { + return {Decision::RECORD_AND_SAMPLE, nullptr}; + } + else + { + return {Decision::NOT_RECORD, nullptr}; } } - if (threshold_ == 0) return { Decision::NOT_RECORD, nullptr }; + if (threshold_ == 0) + return {Decision::NOT_RECORD, nullptr}; if (CalculateThresholdFromBuffer(trace_id) <= threshold_) { - return { Decision::RECORD_AND_SAMPLE, nullptr }; + return {Decision::RECORD_AND_SAMPLE, nullptr}; } - return { Decision::NOT_RECORD, nullptr }; + return {Decision::NOT_RECORD, nullptr}; } nostd::string_view ProbabilitySampler::GetDescription() const noexcept diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index 800b57557a..d939de19f0 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -1,6 +1,7 @@ foreach(testname meter_provider_sdk_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common opentelemetry_metrics) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_common opentelemetry_metrics) gtest_add_tests(TARGET ${testname} TEST_PREFIX metrics. TEST_LIST ${testname}) endforeach() diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 37d27b65c1..52a00d6c58 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -1,5 +1,5 @@ -#include "opentelemetry/sdk/metrics/meter_provider.h" #include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" #include @@ -18,5 +18,4 @@ TEST(MeterProvider, GetMeter) // Should return the same instance each time. ASSERT_EQ(t1, t2); ASSERT_EQ(t1, t3); - } diff --git a/sdk/test/trace/always_off_sampler_test.cc b/sdk/test/trace/always_off_sampler_test.cc index 2c892fcfa7..ce2f11c5b7 100644 --- a/sdk/test/trace/always_off_sampler_test.cc +++ b/sdk/test/trace/always_off_sampler_test.cc @@ -7,24 +7,24 @@ using opentelemetry::sdk::trace::Decision; TEST(AlwaysOffSampler, ShouldSample) { - AlwaysOffSampler sampler; + AlwaysOffSampler sampler; - opentelemetry::trace::TraceId trace_id; - opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; + opentelemetry::trace::TraceId trace_id; + opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; - using M = std::map; - M m1 = {{}}; - opentelemetry::trace::KeyValueIterableView view{m1}; + using M = std::map; + M m1 = {{}}; + opentelemetry::trace::KeyValueIterableView view{m1}; - auto sampling_result = sampler.ShouldSample(nullptr, trace_id, "", span_kind, view); + auto sampling_result = sampler.ShouldSample(nullptr, trace_id, "", span_kind, view); - ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); - ASSERT_EQ(nullptr, sampling_result.attributes); + ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); + ASSERT_EQ(nullptr, sampling_result.attributes); } TEST(AlwaysOffSampler, GetDescription) { - AlwaysOffSampler sampler; + AlwaysOffSampler sampler; - ASSERT_EQ("AlwaysOffSampler", sampler.GetDescription()); + ASSERT_EQ("AlwaysOffSampler", sampler.GetDescription()); } diff --git a/sdk/test/trace/parent_or_else_sampler_test.cc b/sdk/test/trace/parent_or_else_sampler_test.cc index 93ce56dfb1..311ffae59f 100644 --- a/sdk/test/trace/parent_or_else_sampler_test.cc +++ b/sdk/test/trace/parent_or_else_sampler_test.cc @@ -18,14 +18,14 @@ TEST(ParentOrElseSampler, ShouldSample) // Set up parameters opentelemetry::trace::TraceId trace_id; opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; - using M = std::map; - M m1 = {{}}; + using M = std::map; + M m1 = {{}}; opentelemetry::trace::KeyValueIterableView view{m1}; SpanContext parent_context_sampled(true, false); SpanContext parent_context_nonsampled(false, false); // Case 1: Parent doesn't exist. Return result of delegateSampler() - auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view); + auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view); auto sampling_result2 = sampler_on.ShouldSample(nullptr, trace_id, "", span_kind, view); ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); diff --git a/sdk/test/trace/probability_sampler_test.cc b/sdk/test/trace/probability_sampler_test.cc index 37e2a6c943..75a11a1fc7 100644 --- a/sdk/test/trace/probability_sampler_test.cc +++ b/sdk/test/trace/probability_sampler_test.cc @@ -24,9 +24,7 @@ namespace * generate a random trace_id and check if it should sample using the provided * provider and context */ -int RunShouldSampleCountDecision(SpanContext &context, - ProbabilitySampler &sampler, - int iterations) +int RunShouldSampleCountDecision(SpanContext &context, ProbabilitySampler &sampler, int iterations) { int actual_count = 0; From 2d1cdeab256502d80078cab2dfbf62fdf0ab94da Mon Sep 17 00:00:00 2001 From: easy Date: Wed, 29 Jul 2020 16:15:48 +1000 Subject: [PATCH 09/37] Fix format on CI. (#222) --- ci/do_ci.sh | 2 -- tools/format.sh | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index b6d23f763f..b394de03c8 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -107,8 +107,6 @@ elif [[ "$1" == "benchmark" ]]; then exit 0 elif [[ "$1" == "format" ]]; then tools/format.sh - # normalize file endings according to .gitattributes - git add --renormalize . CHANGED="$(git ls-files --modified)" if [[ ! -z "$CHANGED" ]]; then echo "The following files have changes:" diff --git a/tools/format.sh b/tools/format.sh index 1b150dbca3..7d5249d5e3 100755 --- a/tools/format.sh +++ b/tools/format.sh @@ -16,8 +16,9 @@ fi # Correct common miscapitalizations. "${SED[@]}" 's/Open[t]elemetry/OpenTelemetry/g' $($FIND -type f -print) -# No CRLF line endings. -"${SED[@]}" 's/\r$//' $($FIND -type f -print) +# No CRLF line endings, except Windows files. +"${SED[@]}" 's/\r$//' $($FIND -name '*.ps1' -prune -o \ + -name '*.cmd' -prune -o -type f -print) # No trailing spaces. "${SED[@]}" 's/ \+$//' $($FIND -type f -print) From 9195cf7c4679dce5762cf7325f655ead6ededa52 Mon Sep 17 00:00:00 2001 From: easy Date: Wed, 29 Jul 2020 16:48:59 +1000 Subject: [PATCH 10/37] Add shasum for grpc and format file. (#221) --- WORKSPACE | 1 + 1 file changed, 1 insertion(+) diff --git a/WORKSPACE b/WORKSPACE index 9c477b2b43..9aff9c7c29 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -21,6 +21,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # https://github.com/bazelbuild/bazel/issues/6664 http_archive( name = "com_github_grpc_grpc", + sha256 = "d6277f77e0bb922d3f6f56c0f93292bb4cfabfc3c92b31ee5ccea0e100303612", strip_prefix = "grpc-1.28.0", urls = [ "https://github.com/grpc/grpc/archive/v1.28.0.tar.gz", From 4b85762411dae9b3a85d82c9d6ef8768b3047ba8 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Wed, 29 Jul 2020 17:04:53 +0000 Subject: [PATCH 11/37] Add other zpages ex, working emitted static files --- examples/zpages/BUILD | 17 ++++ examples/zpages/zpagesexample.cc | 55 +++++++++++++ .../ext/zpages/static/tracez_index.h | 80 ++++++++++--------- .../ext/zpages/static/tracez_script.h | 12 ++- .../ext/zpages/static/tracez_style.h | 5 ++ .../ext/zpages/tracez_http_server.h | 19 +++-- 6 files changed, 138 insertions(+), 50 deletions(-) create mode 100644 examples/zpages/zpagesexample.cc diff --git a/examples/zpages/BUILD b/examples/zpages/BUILD index 9811ddce23..52703f11f0 100644 --- a/examples/zpages/BUILD +++ b/examples/zpages/BUILD @@ -29,3 +29,20 @@ cc_binary( "//ext/src/zpages", ], ) + + +cc_binary( + name = "zpagesexample", + srcs = [ + "zpagesexample.cc" + ], + linkopts = select({ + "//bazel:windows": [], + "//conditions:default": ["-pthread"], + }), + deps = [ + "//ext:headers", + "//sdk/src/trace", + "//ext/src/zpages", + ], +) diff --git a/examples/zpages/zpagesexample.cc b/examples/zpages/zpagesexample.cc new file mode 100644 index 0000000000..c335f048ae --- /dev/null +++ b/examples/zpages/zpagesexample.cc @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "opentelemetry/ext/zpages/zpages.h" + + std::string GetRandomString() { + std::string s = ""; + const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + for (int i = 0; i < rand() % 8 + 2; ++i) { + s += alphanum[rand() % (sizeof(alphanum) - 1)]; + } + return s; + } + +void MakeUniqueSpans() { + auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(""); + auto span = tracer->StartSpan(GetRandomString()); + if (rand() % 5 == 0) std::this_thread::sleep_for(std::chrono::seconds(rand() % 120)); + else std::this_thread::sleep_for(std::chrono::nanoseconds(rand() % 10000000)); + span->End(); +} + +void MakeSpans(int i) { + auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(""); + auto span = tracer->StartSpan(std::to_string(i)); + if (rand() % 5 == 0) std::this_thread::sleep_for(std::chrono::seconds(rand() % 120)); + else std::this_thread::sleep_for(std::chrono::nanoseconds(rand() % 10000000)); + span->End(); + + +} + +int main(int argc, char* argv[]) { + zPages(); + auto t = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(""); + auto y = t->StartSpan("always running"); + + while (1) { + for (int i = 0; i < 1000; i++) { + //std::thread(MakeSpans, i % 5).detach(); + std::thread(MakeUniqueSpans).detach(); + } + std::cout << "Press for more spans"; + std::cin.get(); + } + y->End(); +} diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_index.h b/ext/include/opentelemetry/ext/zpages/static/tracez_index.h index d0e8e78779..2adf7f15c2 100644 --- a/ext/include/opentelemetry/ext/zpages/static/tracez_index.h +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_index.h @@ -1,42 +1,44 @@ #pragma once const char tracez_index[] = "" - "" - " " - " zPages TraceZ" - " " - " " - " " - " " - " " - "

zPages TraceZ

" - " Last Updated:
" - "
" - "

" - "
" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - "
Span NameError SamplesRunningLatency Samples
" - " " - "
" - "
" - "
" - "
" - " " - "
" - " " - "
" - "
" - " " - ""; +"" +" " +" zPages TraceZ" +" " +" " +" " +" " +" " +"

zPages TraceZ

" +" Last Updated:
" +"
" +"

" +"
" +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +"
Span NameError SamplesRunningLatency Samples
" +" " +"
" +"
Row count: 0
" +"
" +"
" +"
" +" " +"
" +" " +"
" +"
Row count: 0
" +"
" +" " +""; diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_script.h b/ext/include/opentelemetry/ext/zpages/static/tracez_script.h index 730713aff5..d1e5743bd7 100644 --- a/ext/include/opentelemetry/ext/zpages/static/tracez_script.h +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_script.h @@ -1,6 +1,7 @@ #pragma once const char tracez_script[] = "window.onload = () => refreshData();" +"" "const latencies = [" " '>0s', '>10µs', '>100µs'," " '>1ms', '>10ms', '>100ms'," @@ -68,6 +69,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" "};" "" "const base_endpt = '/tracez/get/'; /* For making GET requests */" +"" "/* Maps table types to their approporiate formatting */" "const tableFormatting = {" " 'all': {" @@ -115,7 +117,6 @@ const char tracez_script[] = "window.onload = () => refreshData();" "};" "const getFormat = group => tableFormatting[group];" "" -"" "/* Getters using formatting config variable */" "const getURL = group => getFormat(group)['url'];" "const getHeadings = group => getFormat(group)['headings'];" @@ -181,6 +182,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" " ${detailVal}" " `;" "};" +"" "/* Convert cells to Date strings if needed */" "const getCellContent = (h, span) => {" " if (h in details) return detailCell(h, span);" @@ -188,6 +190,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" " else if (!isDate(h)) return span[h];" " return dateStr(span[h]);" "};" +"" "/* Create cell based on what header we want to render */" "const getCell = (h, span) => (isArrayCol(h)) ? getArrayCells(h, span)" " : ` console.log(err));" "};" @@ -222,7 +227,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" "function updateSubheading(group, name) {" " if (hasSubheading(group)) {" " document.getElementById(getHTML(isLatency(group) ? 'latency' : group) + '_header')" -" .innerHTML = `

${name}
" +" .innerHTML = `

${name}" " ${(isLatency(group) ? `${latencies[group]} Bucket` : toTitlecase(group))}" " Spans

Showing sampled span details (up to 5)." " ${getStatusHTML(group)}

`;" @@ -253,4 +258,5 @@ const char tracez_script[] = "window.onload = () => refreshData();" "const refreshData = () => {" " updateLastRefreshStr();" " overwriteTable('all');" -"};"; +"};" +""; diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_style.h b/ext/include/opentelemetry/ext/zpages/static/tracez_style.h index e80e7556a0..399f53d492 100644 --- a/ext/include/opentelemetry/ext/zpages/static/tracez_style.h +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_style.h @@ -61,6 +61,11 @@ const char tracez_style[] = "body {" " font-weight: bold;" "}" "" +".right {" +" text-align: right;" +" padding: 10px;" +"}" +"" ":hover {" " transition-duration: .15s;" "}" diff --git a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h index d52e25dd9f..3c329eeff4 100644 --- a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h @@ -97,7 +97,7 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { std::string query = GetQuery(req.uri); // tracez if (StartsWith(query, "get")) { - resp.headers[testing::CONTENT_TYPE] = "application/json"; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = "application/json"; query = GetAfterSlash(query); if (StartsWith(query, "latency")) { auto queried_latency_name = GetAfterSlash(query); @@ -116,25 +116,28 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { else if (StartsWith(query, "error")) { resp.body = GetErrorSpansJSON(queried_name).dump(); } - else resp.body = json::array(); + else { + resp.body = json::array(); + } } } else { //resp.body = StartsWith(query, "index.html") ? "cool" : " no "; if (StartsWith(query, "script.js")) { - resp.headers[testing::CONTENT_TYPE] = "text/javascript"; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = "text/javascript"; resp.body = tracez_script; } else if (StartsWith(query, "style.css")) { - resp.headers[testing::CONTENT_TYPE] = "text/css"; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = "text/css"; resp.body = tracez_style; } - else if (query == "/tracez" || query.empty() || StartsWith(query, "index.html")) { - resp.headers[testing::CONTENT_TYPE] = "text/html"; + else if (query.empty() || query == "/tracez" || StartsWith(query, "index.html")) { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = "text/html"; resp.body = tracez_index; } - else { resp.headers[testing::CONTENT_TYPE] = "text/plain"; - resp.body = query; + else { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = "text/plain"; + resp.body = "Invalid query: " + query; } } From 4e2aeee8f38d9928cb443b76cb6f62fbb3c4c8a9 Mon Sep 17 00:00:00 2001 From: Sam Atac <65615762+satac2@users.noreply.github.com> Date: Wed, 29 Jul 2020 14:49:13 -0500 Subject: [PATCH 12/37] Context helper functions (#225) --- .../opentelemetry/context/runtime_context.h | 40 ++++++++++++++++++ api/test/context/runtime_context_test.cc | 41 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/api/include/opentelemetry/context/runtime_context.h b/api/include/opentelemetry/context/runtime_context.h index 7ad3b73bdc..fabd353a84 100644 --- a/api/include/opentelemetry/context/runtime_context.h +++ b/api/include/opentelemetry/context/runtime_context.h @@ -47,6 +47,46 @@ class RuntimeContext static RuntimeContext *context_handler_; + // Sets the Key and Value into the passed in context or if a context is not + // passed in, the RuntimeContext. + // Should be used to SetValues to the current RuntimeContext, is essentially + // equivalent to RuntimeContext::GetCurrent().SetValue(key,value). Keep in + // mind that the current RuntimeContext will not be changed, and the new + // context will be returned. + static Context SetValue(nostd::string_view key, + ContextValue value, + Context *context = nullptr) noexcept + { + Context temp_context; + if (context == nullptr) + { + temp_context = GetCurrent(); + } + else + { + temp_context = *context; + } + return temp_context.SetValue(key, value); + } + + // Returns the value associated with the passed in key and either the + // passed in context* or the runtime context if a context is not passed in. + // Should be used to get values from the current RuntimeContext, is + // essentially equivalent to RuntimeContext::GetCurrent().GetValue(key). + static ContextValue GetValue(nostd::string_view key, Context *context = nullptr) noexcept + { + Context temp_context; + if (context == nullptr) + { + temp_context = GetCurrent(); + } + else + { + temp_context = *context; + } + return temp_context.GetValue(key); + } + protected: // Provides a token with the passed in context Token CreateToken(Context context) noexcept { return Token(context); } diff --git a/api/test/context/runtime_context_test.cc b/api/test/context/runtime_context_test.cc index b70d69dce8..5c0dc565d4 100644 --- a/api/test/context/runtime_context_test.cc +++ b/api/test/context/runtime_context_test.cc @@ -59,3 +59,44 @@ TEST(RuntimeContextTest, ThreeAttachDetach) EXPECT_TRUE(context::RuntimeContext::Detach(foo_context_token)); EXPECT_TRUE(context::RuntimeContext::Detach(test_context_token)); } + +// Tests that SetValue returns a context with the passed in data and the +// RuntimeContext data when a context is not passed into the +// RuntimeContext::SetValue method. +TEST(RuntimeContextTest, SetValueRuntimeContext) +{ + context::Context foo_context = context::Context("foo_key", (int64_t)596); + context::RuntimeContext::Token old_context_token = context::RuntimeContext::Attach(foo_context); + context::Context test_context = context::RuntimeContext::SetValue("test_key", (int64_t)123); + EXPECT_EQ(nostd::get(test_context.GetValue("test_key")), 123); + EXPECT_EQ(nostd::get(test_context.GetValue("foo_key")), 596); +} + +// Tests that SetValue returns a context with the passed in data and the +// passed in context data when a context* is passed into the +// RuntimeContext::SetValue method. +TEST(RuntimeContextTest, SetValueOtherContext) +{ + context::Context foo_context = context::Context("foo_key", (int64_t)596); + context::Context test_context = + context::RuntimeContext::SetValue("test_key", (int64_t)123, &foo_context); + EXPECT_EQ(nostd::get(test_context.GetValue("test_key")), 123); + EXPECT_EQ(nostd::get(test_context.GetValue("foo_key")), 596); +} + +// Tests that SetValue returns the ContextValue associated with the +// passed in string and the current Runtime Context +TEST(RuntimeContextTest, GetValueRuntimeContext) +{ + context::Context foo_context = context::Context("foo_key", (int64_t)596); + context::RuntimeContext::Token old_context_token = context::RuntimeContext::Attach(foo_context); + EXPECT_EQ(nostd::get(context::RuntimeContext::GetValue("foo_key")), 596); +} + +// Tests that SetValue returns the ContextValue associated with the +// passed in string and the passed in context +TEST(RuntimeContextTest, GetValueOtherContext) +{ + context::Context foo_context = context::Context("foo_key", (int64_t)596); + EXPECT_EQ(nostd::get(context::RuntimeContext::GetValue("foo_key", &foo_context)), 596); +} From 41af3aca9d67f04e2b2bab7320f3ed9e6fea0b87 Mon Sep 17 00:00:00 2001 From: Ankit Bhargava Date: Thu, 30 Jul 2020 00:46:40 -0400 Subject: [PATCH 13/37] Add Counter and Histogram Aggregators (#178) --- .../sdk/metrics/aggregator/aggregator.h | 141 +++++++++++++ .../metrics/aggregator/counter_aggregator.h | 101 +++++++++ .../metrics/aggregator/histogram_aggregator.h | 197 ++++++++++++++++++ sdk/test/metrics/BUILD | 22 ++ sdk/test/metrics/counter_aggregator_test.cc | 115 ++++++++++ sdk/test/metrics/histogram_aggregator_test.cc | 167 +++++++++++++++ 6 files changed, 743 insertions(+) create mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h create mode 100644 sdk/test/metrics/counter_aggregator_test.cc create mode 100644 sdk/test/metrics/histogram_aggregator_test.cc diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h new file mode 100644 index 0000000000..b997514208 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include "opentelemetry/core/timestamp.h" +#include "opentelemetry/metrics/instrument.h" +#include "opentelemetry/version.h" + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +enum class AggregatorKind +{ + Counter = 0, + MinMaxSumCount = 1, + Gauge = 2, + Sketch = 3, + Histogram = 4, + Exact = 5, +}; + +/* + * Performs calculations necessary to combine updates from instruments into an + * insightful value. + * Also stores current instrument values and checkpoints collected at intervals + * governing the entire pipeline. + */ +template +class Aggregator +{ +public: + Aggregator() = default; + + virtual ~Aggregator() = default; + + /** + * Receives a captured value from the instrument and applies it to the current aggregator value. + * + * @param val, the raw value used in aggregation + * @return none + */ + virtual void update(T val) = 0; + + /** + * Checkpoints the current value. This function will overwrite the current checkpoint with the + * current value. + * + * @param none + * @return none + */ + virtual void checkpoint() = 0; + + /** + * Merges the values of two aggregators in a semantically accurate manner. + * Merging will occur differently for different aggregators depending on the + * way values are tracked. + * + * @param other, the aggregator with merge with + * @return none + */ + void merge(Aggregator *other); + + /** + * Returns the checkpointed value + * + * @param none + * @return the value of the checkpoint + */ + virtual std::vector get_checkpoint() = 0; + + /** + * Returns the current value + * + * @param none + * @return the present aggregator value + */ + virtual std::vector get_values() = 0; + + /** + * Returns the instrument kind which this aggregator is associated with + * + * @param none + * @return the InstrumentKind of the aggregator's owner + */ + virtual opentelemetry::metrics::InstrumentKind get_instrument_kind() final { return kind_; } + + /** + * Returns the type of this aggregator + * + * @param none + * @return the AggregatorKind of this instrument + */ + virtual AggregatorKind get_aggregator_kind() final { return agg_kind_; } + + // virtual function to be overriden for the Histogram Aggregator + virtual std::vector get_boundaries() { return std::vector(); } + + // virtual function to be overriden for the Histogram Aggregator + virtual std::vector get_counts() { return std::vector(); } + + // virtual function to be overriden for Exact and Sketch Aggregators + virtual bool get_quant_estimation() { return false; } + + // virtual function to be overriden for Exact and Sketch Aggregators + virtual T get_quantiles(double q) { return values_[0]; } + + // virtual function to be overriden for Sketch Aggregator + virtual double get_error_bound() { return 0; } + + // virtual function to be overriden for Sketch Aggregator + virtual size_t get_max_buckets() { return 0; } + + // virtual function to be overriden for Gauge Aggregator + virtual core::SystemTimestamp get_checkpoint_timestamp() { return core::SystemTimestamp(); } + + // Custom copy constructor to handle the mutex + Aggregator(const Aggregator &cp) + { + values_ = cp.values_; + checkpoint_ = cp.checkpoint_; + kind_ = cp.kind_; + agg_kind_ = cp.agg_kind_; + // use default initialized mutex as they cannot be copied + } + +protected: + std::vector values_; + std::vector checkpoint_; + opentelemetry::metrics::InstrumentKind kind_; + std::mutex mu_; + AggregatorKind agg_kind_; +}; + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h new file mode 100644 index 0000000000..0bf44f6421 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h @@ -0,0 +1,101 @@ +#pragma once + +#include +#include +#include "opentelemetry/metrics/instrument.h" +#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" +#include "opentelemetry/version.h" + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +template +class CounterAggregator final : public Aggregator +{ + +public: + CounterAggregator(metrics_api::InstrumentKind kind) + { + this->kind_ = kind; + this->values_ = std::vector(1, 0); + this->checkpoint_ = std::vector(1, 0); + this->agg_kind_ = AggregatorKind::Counter; + } + + /** + * Recieves a captured value from the instrument and applies it to the current aggregator value. + * + * @param val, the raw value used in aggregation + * @return none + */ + void update(T val) override + { + this->mu_.lock(); + this->values_[0] += val; // atomic operation + this->mu_.unlock(); + } + + /** + * Checkpoints the current value. This function will overwrite the current checkpoint with the + * current value. + * + * @param none + * @return none + */ + void checkpoint() override + { + this->checkpoint_ = this->values_; + this->values_[0] = 0; + } + + /** + * Merges the values of two aggregators in a semantically accurate manner. + * In this case, merging only requires the the current values of the two aggregators be summed. + * + * @param other, the aggregator with merge with + * @return none + */ + void merge(CounterAggregator other) + { + if (this->agg_kind_ == other.agg_kind_) + { + this->mu_.lock(); + this->values_[0] += other.values_[0]; + this->checkpoint_[0] += other.checkpoint_[0]; + this->mu_.unlock(); + } + else + { +#if __EXCEPTIONS + throw std::invalid_argument("Aggregators of different types cannot be merged."); +#else + std::terminate(); +#endif + } + } + + /** + * Returns the checkpointed value + * + * @param none + * @return the value of the checkpoint + */ + virtual std::vector get_checkpoint() override { return this->checkpoint_; } + + /** + * Returns the current values + * + * @param none + * @return the present aggregator values + */ + virtual std::vector get_values() override { return this->values_; } +}; + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h new file mode 100644 index 0000000000..78b024eaec --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h @@ -0,0 +1,197 @@ +#pragma once + +#include +#include +#include +#include +#include "opentelemetry/metrics/instrument.h" +#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" +#include "opentelemetry/version.h" + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +template +class HistogramAggregator final : public Aggregator +{ + +public: + /** + * Constructor for the histogram aggregator. A sorted vector of boundaries is expected and + * boundaries are doubles regardless of the aggregator's templated data type. + * + * Sum is stored in values_[0] + * Count is stored in position_[1] + */ + HistogramAggregator(metrics_api::InstrumentKind kind, std::vector boundaries) + { + if (!std::is_sorted(boundaries.begin(), boundaries.end())) + { +#if __EXCEPTIONS + throw std::invalid_argument("Histogram boundaries must be monotonic."); +#else + std::terminate(); +#endif + } + this->kind_ = kind; + this->agg_kind_ = AggregatorKind::Histogram; + boundaries_ = boundaries; + this->values_ = std::vector(2, 0); + this->checkpoint_ = std::vector(2, 0); + bucketCounts_ = std::vector(boundaries_.size() + 1, 0); + bucketCounts_ckpt_ = std::vector(boundaries_.size() + 1, 0); + } + + /** + * Recieves a captured value from the instrument and inserts it into the current histogram counts. + * + * Depending on the use case, a linear search or binary search based implementation may be + * preferred. In uniformly distributed datasets, linear search outperforms binary search until 512 + * buckets. However, if the distribution is strongly skewed right (for example server latency + * where most values may be <10ms but the range is from 0 - 1000 ms), a linear search could be + * superior even with more than 500 buckets as almost all values inserted would be at the + * beginning of the boundaries array and thus found more quickly through linear search. + * + * @param val, the raw value used in aggregation + * @return none + */ + void update(T val) override + { + int bucketID = boundaries_.size(); + for (size_t i = 0; i < boundaries_.size(); i++) + { + if (val < boundaries_[i]) // concurrent read is thread-safe + { + bucketID = i; + break; + } + } + + // Alternate implementation with binary search + // auto pos = std::lower_bound (boundaries_.begin(), boundaries_.end(), val); + // bucketCounts_[pos-boundaries_.begin()] += 1; + + this->mu_.lock(); + this->values_[0] += val; + this->values_[1] += 1; + bucketCounts_[bucketID] += 1; + this->mu_.unlock(); + } + + /** + * Checkpoints the current value. This function will overwrite the current checkpoint with the + * current value. + * + * @param none + * @return none + */ + void checkpoint() override + { + this->checkpoint_ = this->values_; + this->values_[0] = 0; + this->values_[1] = 0; + bucketCounts_ckpt_ = bucketCounts_; + std::fill(bucketCounts_.begin(), bucketCounts_.end(), 0); + } + + /** + * Merges the values of two aggregators in a semantically accurate manner. + * A histogram aggregator can only be merged with another histogram aggregator that has the same + * boudnaries. A histogram merge first adds the sum and count values then iterates over the adds + * the bucket counts element by element. + * + * @param other, the aggregator with merge with + * @return none + */ + void merge(HistogramAggregator other) + { + this->mu_.lock(); + + // Ensure that incorrect types are not merged + if (this->agg_kind_ != other.agg_kind_) + { +#if __EXCEPTIONS + throw std::invalid_argument("Aggregators of different types cannot be merged."); +#else + std::terminate(); +#endif + // Reject histogram merges with differing boundary vectors + } + else if (other.boundaries_ != this->boundaries_) + { +#if __EXCEPTIONS + throw std::invalid_argument("Histogram boundaries do not match."); +#else + std::terminate(); +#endif + } + + this->values_[0] += other.values_[0]; + this->values_[1] += other.values_[1]; + + for (size_t i = 0; i < bucketCounts_.size(); i++) + { + bucketCounts_[i] += other.bucketCounts_[i]; + bucketCounts_ckpt_[i] += other.bucketCounts_ckpt_[i]; + } + this->mu_.unlock(); + } + + /** + * Returns the checkpointed value + * + * @param none + * @return the value of the checkpoint + */ + std::vector get_checkpoint() override { return this->checkpoint_; } + + /** + * Returns the current values + * + * @param none + * @return the present aggregator values + */ + std::vector get_values() override { return this->values_; } + + /** + * Returns the bucket boundaries specified at this aggregator's creation. + * + * @param none + * @return the aggregator boundaries + */ + virtual std::vector get_boundaries() override { return boundaries_; } + + /** + * Returns the current counts for each bucket . + * + * @param none + * @return the aggregator bucket counts + */ + virtual std::vector get_counts() override { return bucketCounts_ckpt_; } + + HistogramAggregator(const HistogramAggregator &cp) + { + this->values_ = cp.values_; + this->checkpoint_ = cp.checkpoint_; + this->kind_ = cp.kind_; + this->agg_kind_ = cp.agg_kind_; + boundaries_ = cp.boundaries_; + bucketCounts_ = cp.bucketCounts_; + bucketCounts_ckpt_ = cp.bucketCounts_ckpt_; + // use default initialized mutex as they cannot be copied + } + +private: + std::vector boundaries_; + std::vector bucketCounts_; + std::vector bucketCounts_ckpt_; +}; + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD index e2d5c5cb71..4ce50b36e2 100644 --- a/sdk/test/metrics/BUILD +++ b/sdk/test/metrics/BUILD @@ -8,3 +8,25 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "counter_aggregator_test", + srcs = [ + "counter_aggregator_test.cc", + ], + deps = [ + "//sdk/src/metrics", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "histogram_aggregator_test", + srcs = [ + "histogram_aggregator_test.cc", + ], + deps = [ + "//sdk/src/metrics", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/metrics/counter_aggregator_test.cc b/sdk/test/metrics/counter_aggregator_test.cc new file mode 100644 index 0000000000..1e2b1dce8c --- /dev/null +++ b/sdk/test/metrics/counter_aggregator_test.cc @@ -0,0 +1,115 @@ +#include "opentelemetry/sdk/metrics/aggregator/counter_aggregator.h" + +#include +#include +#include + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +TEST(CounterAggregator, NoUpdates) +{ + CounterAggregator alpha(metrics_api::InstrumentKind::Counter); + + EXPECT_EQ(alpha.get_checkpoint().size(), 1); + EXPECT_EQ(alpha.get_checkpoint()[0], 0); + + alpha.checkpoint(); + EXPECT_EQ(alpha.get_checkpoint().size(), 1); + EXPECT_EQ(alpha.get_checkpoint()[0], 0); +} + +TEST(CounterAggregator, Update) +{ + CounterAggregator alpha(metrics_api::InstrumentKind::Counter); + CounterAggregator beta(metrics_api::InstrumentKind::Counter); + + for (int i = 0; i < 123456; i++) + { + alpha.update(1); + } + + int sum = 0; + for (int i = 0; i < 100; i++) + { + int tmp = std::rand(); + beta.update(tmp); + sum += tmp; + } + + EXPECT_EQ(alpha.get_checkpoint()[0], 0); // checkpoint shouldn't change even with updates + EXPECT_EQ(beta.get_checkpoint()[0], 0); + + alpha.checkpoint(); + beta.checkpoint(); + + EXPECT_EQ(alpha.get_checkpoint()[0], 123456); + EXPECT_EQ(beta.get_checkpoint()[0], sum); + + alpha.update(15); + alpha.checkpoint(); + EXPECT_EQ(alpha.get_checkpoint()[0], 15); // reset to 0 after first checkpoint call +} + +// callback update function used to test concurrent calls +void incrementingCallback(Aggregator &agg) +{ + for (int i = 0; i < 2000000; i++) + { + agg.update(1); + } +} + +TEST(CounterAggregator, Concurrency) +{ + CounterAggregator alpha(metrics_api::InstrumentKind::Counter); + + // spawn new threads that initiate the callback + std::thread first(incrementingCallback, std::ref(alpha)); + std::thread second(incrementingCallback, std::ref(alpha)); + + first.join(); + second.join(); + + alpha.checkpoint(); + + // race conditions result in values below 2*2000000 + EXPECT_EQ(alpha.get_checkpoint()[0], 2 * 2000000); +} + +TEST(CounterAggregator, Merge) +{ + CounterAggregator alpha(metrics_api::InstrumentKind::Counter); + CounterAggregator beta(metrics_api::InstrumentKind::Counter); + + alpha.merge(beta); + + alpha.checkpoint(); + EXPECT_EQ(alpha.get_checkpoint()[0], 0); // merge with no updates + + for (int i = 0; i < 500; i++) + { + alpha.update(1); + } + + for (int i = 0; i < 700; i++) + { + beta.update(1); + } + + alpha.merge(beta); + alpha.checkpoint(); + EXPECT_EQ(alpha.get_checkpoint()[0], 1200); + + // HistogramAggregator gamma(metrics_api::BoundInstrumentKind::BoundValueRecorder); + // ASSERT_THROW(alpha.merge(gamma), AggregatorMismatch); +} + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/metrics/histogram_aggregator_test.cc b/sdk/test/metrics/histogram_aggregator_test.cc new file mode 100644 index 0000000000..146c552bb0 --- /dev/null +++ b/sdk/test/metrics/histogram_aggregator_test.cc @@ -0,0 +1,167 @@ +#include "opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h" + +#include +#include +#include +#include +// #include + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +// Test updating with a uniform set of updates +TEST(Histogram, Uniform) +{ + std::vector boundaries{10, 20, 30, 40, 50}; + HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); + + EXPECT_EQ(alpha.get_aggregator_kind(), AggregatorKind::Histogram); + + alpha.checkpoint(); + EXPECT_EQ(alpha.get_checkpoint().size(), 2); + EXPECT_EQ(alpha.get_counts().size(), 6); + + for (int i = 0; i < 60; i++) + { + alpha.update(i); + } + + alpha.checkpoint(); + + EXPECT_EQ(alpha.get_checkpoint()[0], 1770); + EXPECT_EQ(alpha.get_checkpoint()[1], 60); + + std::vector correct = {10, 10, 10, 10, 10, 10}; + EXPECT_EQ(alpha.get_counts(), correct); +} + +// Test updating with a normal distribution +TEST(Histogram, Normal) +{ + std::vector boundaries{2, 4, 6, 8, 10, 12}; + HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); + + std::vector vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13}; + for (int i : vals) + { + alpha.update(i); + } + + alpha.checkpoint(); + + EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0)); + EXPECT_EQ(alpha.get_checkpoint()[1], vals.size()); + + std::vector correct = {1, 2, 3, 4, 3, 2, 1}; + EXPECT_EQ(alpha.get_counts(), correct); +} + +TEST(Histogram, Merge) +{ + std::vector boundaries{2, 4, 6, 8, 10, 12}; + HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); + HistogramAggregator beta(metrics_api::InstrumentKind::Counter, boundaries); + + std::vector vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13}; + for (int i : vals) + { + alpha.update(i); + } + + std::vector otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15}; + for (int i : otherVals) + { + beta.update(i); + } + + alpha.merge(beta); + alpha.checkpoint(); + + EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) + + std::accumulate(otherVals.begin(), otherVals.end(), 0)); + EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size()); + + std::vector correct = {5, 2, 3, 4, 3, 4, 5}; + EXPECT_EQ(alpha.get_counts(), correct); +} + +// Update callback used to validate multi-threaded performance +void histogramUpdateCallback(Aggregator &agg, std::vector vals) +{ + for (int i : vals) + { + agg.update(i); + } +} + +int randVal() +{ + return rand() % 15; +} + +TEST(Histogram, Concurrency) +{ + std::vector boundaries{2, 4, 6, 8, 10, 12}; + HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); + + std::vector vals1(1000); + std::generate(vals1.begin(), vals1.end(), randVal); + + std::vector vals2(1000); + std::generate(vals2.begin(), vals2.end(), randVal); + + std::thread first(histogramUpdateCallback, std::ref(alpha), vals1); + std::thread second(histogramUpdateCallback, std::ref(alpha), vals2); + + first.join(); + second.join(); + + HistogramAggregator beta(metrics_api::InstrumentKind::Counter, boundaries); + + // Timing harness to compare linear and binary insertion + // auto start = std::chrono::system_clock::now(); + for (int i : vals1) + { + beta.update(i); + } + for (int i : vals2) + { + beta.update(i); + } + // auto end = std::chrono::system_clock::now(); + // auto elapsed = std::chrono::duration_cast(end - start); + // std::cout <<"Update time: " < boundaries{2, 4, 6, 8, 10, 12}; + std::vector boundaries2{1, 4, 6, 8, 10, 12}; + std::vector unsortedBoundaries{10, 12, 4, 6, 8}; + EXPECT_ANY_THROW( + HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, unsortedBoundaries)); + + HistogramAggregator beta(metrics_api::InstrumentKind::Counter, boundaries); + HistogramAggregator gamma(metrics_api::InstrumentKind::Counter, boundaries2); + + EXPECT_ANY_THROW(beta.merge(gamma)); +} + +#endif + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE From 4caf0bbb0daf9620182b1900de66f381a91d9db8 Mon Sep 17 00:00:00 2001 From: Brandon Kimberly Date: Thu, 30 Jul 2020 10:39:49 -0400 Subject: [PATCH 14/37] Add MinMaxSumCount and Gauge Aggregators (#181) --- sdk/include/opentelemetry/sdk/metrics/TBD | 0 .../sdk/metrics/aggregator/gauge_aggregator.h | 138 ++++++++++++ .../aggregator/min_max_sum_count_aggregator.h | 154 +++++++++++++ sdk/test/metrics/BUILD | 22 ++ sdk/test/metrics/CMakeLists.txt | 8 +- sdk/test/metrics/gauge_aggregator_test.cc | 127 +++++++++++ .../min_max_sum_count_aggregator_test.cc | 203 ++++++++++++++++++ 7 files changed, 648 insertions(+), 4 deletions(-) delete mode 100644 sdk/include/opentelemetry/sdk/metrics/TBD create mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h create mode 100644 sdk/test/metrics/gauge_aggregator_test.cc create mode 100644 sdk/test/metrics/min_max_sum_count_aggregator_test.cc diff --git a/sdk/include/opentelemetry/sdk/metrics/TBD b/sdk/include/opentelemetry/sdk/metrics/TBD deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h new file mode 100644 index 0000000000..7925f5e205 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h @@ -0,0 +1,138 @@ +#pragma once + +#include "opentelemetry/core/timestamp.h" +#include "opentelemetry/metrics/instrument.h" +#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" +#include "opentelemetry/version.h" + +#include +#include +#include + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +/** + * This aggregator stores and maintains a vector of + * type T where the contents of the vector simply + * include the last value recorded to the aggregator. + * The aggregator also maintains a timestamp of when + * the last value was recorded. + * + * @tparam T the type of values stored in this aggregator. + */ +template +class GaugeAggregator : public Aggregator +{ +public: + explicit GaugeAggregator(metrics_api::InstrumentKind kind) + { + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + this->kind_ = kind; + this->values_ = std::vector(1, 0); + this->checkpoint_ = this->values_; + this->agg_kind_ = AggregatorKind::Gauge; + current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); + } + + ~GaugeAggregator() = default; + + GaugeAggregator(const GaugeAggregator &cp) + { + this->values_ = cp.values_; + this->checkpoint_ = cp.checkpoint_; + this->kind_ = cp.kind_; + this->agg_kind_ = cp.agg_kind_; + current_timestamp_ = cp.current_timestamp_; + // use default initialized mutex as they cannot be copied + } + + /** + * Receives a captured value from the instrument and applies it to the current aggregator value. + * + * @param val, the raw value used in aggregation + */ + void update(T val) override + { + this->mu_.lock(); + this->values_[0] = val; + current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); + this->mu_.unlock(); + } + + /** + * Checkpoints the current value. This function will overwrite the current checkpoint with the + * current value. + * + * @return none + */ + + void checkpoint() override + { + this->mu_.lock(); + + this->checkpoint_ = this->values_; + + // Reset the values to default + this->values_[0] = 0; + checkpoint_timestamp_ = current_timestamp_; + current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); + + this->mu_.unlock(); + } + + /** + * Merges two Gauge aggregators together + * + * @param other the aggregator to merge with this aggregator + */ + void merge(GaugeAggregator other) + { + if (this->kind_ == other.kind_) + { + this->mu_.lock(); + // First merge values + this->values_[0] = other.values_[0]; + // Now merge checkpoints + this->checkpoint_[0] = other.checkpoint_[0]; + current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); + this->mu_.unlock(); + } + else + { + // Log error + return; + } + } + + /** + * @return the value of the latest checkpoint + */ + std::vector get_checkpoint() override { return this->checkpoint_; } + + /** + * @return the latest checkpointed timestamp + */ + core::SystemTimestamp get_checkpoint_timestamp() override { return checkpoint_timestamp_; } + + /** + * @return the values_ vector stored in this aggregator + */ + std::vector get_values() override { return this->values_; } + + /** + * @return the timestamp of when the last value recorded + */ + core::SystemTimestamp get_timestamp() { return current_timestamp_; } + +private: + core::SystemTimestamp current_timestamp_; + core::SystemTimestamp checkpoint_timestamp_; +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h new file mode 100644 index 0000000000..b47cf0df06 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h @@ -0,0 +1,154 @@ +#pragma once + +#include "opentelemetry/metrics/instrument.h" +#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" +#include "opentelemetry/version.h" + +#include +#include +#include + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +const int MinValueIndex = 0; +const int MaxValueIndex = 1; +const int SumValueIndex = 2; +const int CountValueIndex = 3; +/** + * This aggregator stores and maintains a vector of + * type T where the contents in the vector are made + * up of the minimum value recorded to this instrument, + * the maximum value, the sum of all values, and the + * count of all values. + * + * @tparam T the type of values stored in this aggregator. + */ +template +class MinMaxSumCountAggregator : public Aggregator +{ +public: + explicit MinMaxSumCountAggregator(metrics_api::InstrumentKind kind) + { + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + this->kind_ = kind; + this->values_ = std::vector(4, 0); // {min, max, sum, count} + this->checkpoint_ = this->values_; + this->agg_kind_ = AggregatorKind::MinMaxSumCount; + } + + ~MinMaxSumCountAggregator() = default; + + MinMaxSumCountAggregator(const MinMaxSumCountAggregator &cp) + { + this->values_ = cp.values_; + this->checkpoint_ = cp.checkpoint_; + this->kind_ = cp.kind_; + this->agg_kind_ = cp.agg_kind_; + // use default initialized mutex as they cannot be copied + } + + /** + * Receives a captured value from the instrument and applies it to the current aggregator value. + * + * @param val, the raw value used in aggregation + */ + void update(T val) override + { + this->mu_.lock(); + + if (this->values_[CountValueIndex] == 0 || val < this->values_[MinValueIndex]) // set min + this->values_[MinValueIndex] = val; + if (this->values_[CountValueIndex] == 0 || val > this->values_[MaxValueIndex]) // set max + this->values_[MaxValueIndex] = val; + + this->values_[SumValueIndex] += val; // compute sum + this->values_[CountValueIndex]++; // increment count + + this->mu_.unlock(); + } + + /** + * Checkpoints the current value. This function will overwrite the current checkpoint with the + * current value. + * + */ + void checkpoint() override + { + this->mu_.lock(); + this->checkpoint_ = this->values_; + // Reset the values + this->values_[MinValueIndex] = 0; + this->values_[MaxValueIndex] = 0; + this->values_[SumValueIndex] = 0; + this->values_[CountValueIndex] = 0; + this->mu_.unlock(); + } + + /** + * Merges two MinMaxSumCount aggregators together + * + * @param other the aggregator to merge with this aggregator + */ + void merge(const MinMaxSumCountAggregator &other) + { + if (this->kind_ == other.kind_) + { + this->mu_.lock(); + // First merge values + // set min + if (this->values_[CountValueIndex] == 0 || + other.values_[MinValueIndex] < this->values_[MinValueIndex]) + this->values_[MinValueIndex] = other.values_[MinValueIndex]; + // set max + if (this->values_[CountValueIndex] == 0 || + other.values_[MaxValueIndex] > this->values_[MaxValueIndex]) + this->values_[MaxValueIndex] = other.values_[MaxValueIndex]; + // set sum + this->values_[SumValueIndex] += other.values_[SumValueIndex]; + // set count + this->values_[CountValueIndex] += other.values_[CountValueIndex]; + + // Now merge checkpoints + if (this->checkpoint_[CountValueIndex] == 0 || + other.checkpoint_[MinValueIndex] < this->checkpoint_[MinValueIndex]) + this->checkpoint_[MinValueIndex] = other.checkpoint_[MinValueIndex]; + // set max + if (this->checkpoint_[CountValueIndex] == 0 || + other.checkpoint_[MaxValueIndex] > this->checkpoint_[MaxValueIndex]) + this->checkpoint_[MaxValueIndex] = other.checkpoint_[MaxValueIndex]; + // set sum + this->checkpoint_[SumValueIndex] += other.checkpoint_[SumValueIndex]; + // set count + this->checkpoint_[CountValueIndex] += other.checkpoint_[CountValueIndex]; + + this->mu_.unlock(); + } + else + { + // Log error + return; + } + } + + /** + * Returns the checkpointed value + * + * @return the value of the checkpoint + */ + std::vector get_checkpoint() override { return this->checkpoint_; } + + /** + * Returns the values currently held by the aggregator + * + * @return the values held by the aggregator + */ + std::vector get_values() override { return this->values_; } +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD index 4ce50b36e2..ec3ec362ab 100644 --- a/sdk/test/metrics/BUILD +++ b/sdk/test/metrics/BUILD @@ -1,3 +1,25 @@ +cc_test( + name = "gauge_aggregator_test", + srcs = [ + "gauge_aggregator_test.cc", + ], + deps = [ + "//sdk/src/metrics", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "min_max_sum_count_aggregator_test", + srcs = [ + "min_max_sum_count_aggregator_test.cc", + ], + deps = [ + "//sdk/src/metrics", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "meter_provider_sdk_test", srcs = [ diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index d939de19f0..3d906b6bcb 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -1,7 +1,7 @@ -foreach(testname meter_provider_sdk_test) +foreach(testname meter_provider_sdk_test gauge_aggregator_test + min_max_sum_count_aggregator_test) add_executable(${testname} "${testname}.cc") - target_link_libraries( - ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_common opentelemetry_metrics) + target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics) gtest_add_tests(TARGET ${testname} TEST_PREFIX metrics. TEST_LIST ${testname}) endforeach() diff --git a/sdk/test/metrics/gauge_aggregator_test.cc b/sdk/test/metrics/gauge_aggregator_test.cc new file mode 100644 index 0000000000..7370d78f70 --- /dev/null +++ b/sdk/test/metrics/gauge_aggregator_test.cc @@ -0,0 +1,127 @@ +#include +#include + +#include "opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h" + +using namespace opentelemetry::sdk::metrics; + +TEST(GaugeAggregator, Update) +{ + // This tests that the aggregator updates the maintained value correctly + // after a call to the update() function. + auto agg = new GaugeAggregator(opentelemetry::metrics::InstrumentKind::Counter); + + // Verify default value + ASSERT_EQ(agg->get_values()[0], 0); + + // Verify that the value updates correctly + agg->update(1); + ASSERT_EQ(agg->get_values()[0], 1); + + // Verify that the value continually updates correctly + for (int i = 0; i < 10; ++i) + { + agg->update(i); + } + ASSERT_EQ(agg->get_values()[0], 9); + delete agg; +} + +TEST(GaugeAggregator, Checkpoint) +{ + // This tests that the aggregator correctly updates the + // checkpoint_ value after a call to update() followed + // by a call to checkpoint(). + GaugeAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + // Verify default checkpoint, before updates + ASSERT_EQ(agg.get_checkpoint()[0], 0); + + agg.update(10); + agg.checkpoint(); + + // Verify that the new checkpoint contains the update value + ASSERT_EQ(agg.get_checkpoint()[0], 10); +} + +TEST(GaugeAggregator, Merge) +{ + // This tests that the values_ vector is updated correctly after + // two aggregators are merged together. + GaugeAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); + GaugeAggregator agg2(opentelemetry::metrics::InstrumentKind::Counter); + + agg1.update(1); + agg2.update(2); + + agg1.merge(agg2); + + // Verify that the aggregators merged and the value was updated correctly + ASSERT_EQ(agg1.get_values()[0], 2); +} + +TEST(GaugeAggregator, BadMerge) +{ + // This verifies that we encounter and error when we try to merge + // two aggregators of different numeric types together. + GaugeAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); + GaugeAggregator agg2(opentelemetry::metrics::InstrumentKind::ValueRecorder); + + agg1.update(1); + agg2.update(2); + agg1.merge(agg2); + + // Verify that the aggregators did NOT merge + std::vector correct{1}; + ASSERT_EQ(agg1.get_values(), correct); +} + +TEST(GaugeAggregator, Types) +{ + // This test verifies that we do not encounter any errors when + // using various numeric types. + GaugeAggregator agg_int(opentelemetry::metrics::InstrumentKind::Counter); + GaugeAggregator agg_long(opentelemetry::metrics::InstrumentKind::Counter); + GaugeAggregator agg_float(opentelemetry::metrics::InstrumentKind::Counter); + GaugeAggregator agg_double(opentelemetry::metrics::InstrumentKind::Counter); + + for (int i = 1; i <= 10; ++i) + { + agg_int.update(i); + agg_long.update(i); + } + + for (float i = 1.0; i <= 10.0; i += 1) + { + agg_float.update(i); + agg_double.update(i); + } + + ASSERT_EQ(agg_int.get_values()[0], 10); + ASSERT_EQ(agg_long.get_values()[0], 10); + ASSERT_EQ(agg_float.get_values()[0], 10.0); + ASSERT_EQ(agg_double.get_values()[0], 10.0); +} + +static void callback(GaugeAggregator &agg) +{ + for (int i = 1; i <= 10000; ++i) + { + agg.update(i); + } +} + +TEST(GaugeAggregator, Concurrency) +{ + // This test checks that the aggregator updates appropriately + // when called in a multi-threaded context. + GaugeAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + std::thread first(&callback, std::ref(agg)); + std::thread second(&callback, std::ref(agg)); + + first.join(); + second.join(); + + ASSERT_EQ(agg.get_values()[0], 10000); +} \ No newline at end of file diff --git a/sdk/test/metrics/min_max_sum_count_aggregator_test.cc b/sdk/test/metrics/min_max_sum_count_aggregator_test.cc new file mode 100644 index 0000000000..21d06ddcea --- /dev/null +++ b/sdk/test/metrics/min_max_sum_count_aggregator_test.cc @@ -0,0 +1,203 @@ +#include +#include + +#include "opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h" + +using namespace opentelemetry::sdk::metrics; + +TEST(MinMaxSumCountAggregator, Update) +{ + // This tests that the aggregator updates the maintained value correctly + // after a call to the update() function. + MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + auto value_set = agg.get_values(); + ASSERT_EQ(value_set[0], 0); + ASSERT_EQ(value_set[1], 0); + ASSERT_EQ(value_set[2], 0); + ASSERT_EQ(value_set[3], 0); + + // 1 + 2 + 3 + ... + 10 = 55 + for (int i = 1; i <= 10; ++i) + { + agg.update(i); + } + + value_set = agg.get_values(); + ASSERT_EQ(value_set[0], 1); // min + ASSERT_EQ(value_set[1], 10); // max + ASSERT_EQ(value_set[2], 55); // sum + ASSERT_EQ(value_set[3], 10); // count +} + +TEST(MinMaxSumCountAggregator, FirstUpdate) +{ + // This tests that the aggregator appropriately maintains the min and + // max values after a single update call. + MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + agg.update(1); + auto value_set = agg.get_values(); + ASSERT_EQ(value_set[0], 1); // min + ASSERT_EQ(value_set[1], 1); // max + ASSERT_EQ(value_set[2], 1); // sum + ASSERT_EQ(value_set[3], 1); // count +} + +TEST(MinMaxSumCountAggregator, Checkpoint) +{ + // This test verifies that the default checkpoint is set correctly + // and that the checkpoint values update correctly after a call + // to the checkpoint() function. + MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + // Verify that the default checkpoint is set correctly. + auto checkpoint_set = agg.get_checkpoint(); + ASSERT_EQ(checkpoint_set[0], 0); // min + ASSERT_EQ(checkpoint_set[1], 0); // max + ASSERT_EQ(checkpoint_set[2], 0); // sum + ASSERT_EQ(checkpoint_set[3], 0); // count + + // 1 + 2 + 3 + ... + 10 = 55 + for (int i = 1; i <= 10; ++i) + { + agg.update(i); + } + + agg.checkpoint(); + + // Verify that the checkpoint values were updated. + checkpoint_set = agg.get_checkpoint(); + ASSERT_EQ(checkpoint_set[0], 1); // min + ASSERT_EQ(checkpoint_set[1], 10); // max + ASSERT_EQ(checkpoint_set[2], 55); // sum + ASSERT_EQ(checkpoint_set[3], 10); // count + + // Verify that the current values were reset to the default state. + auto value_set = agg.get_values(); + ASSERT_EQ(value_set[0], 0); // min + ASSERT_EQ(value_set[1], 0); // max + ASSERT_EQ(value_set[2], 0); // sum + ASSERT_EQ(value_set[3], 0); // count +} + +TEST(MinMaxSumCountAggregator, Merge) +{ + // This tests that the values_ vector is updated correctly after + // two aggregators are merged together. + MinMaxSumCountAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); + MinMaxSumCountAggregator agg2(opentelemetry::metrics::InstrumentKind::Counter); + + // 1 + 2 + 3 + ... + 10 = 55 + for (int i = 1; i <= 10; ++i) + { + agg1.update(i); + } + + // 1 + 2 + 3 + ... + 20 = 210 + for (int i = 1; i <= 20; ++i) + { + agg2.update(i); + } + + agg1.merge(agg2); + + // Verify that the current values were changed by the merge. + auto value_set = agg1.get_values(); + ASSERT_EQ(value_set[0], 1); // min + ASSERT_EQ(value_set[1], 20); // max + ASSERT_EQ(value_set[2], 265); // sum + ASSERT_EQ(value_set[3], 30); // count +} + +TEST(MinMaxSumCountAggregator, BadMerge) +{ + // This verifies that we encounter and error when we try to merge + // two aggregators of different numeric types together. + MinMaxSumCountAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); + MinMaxSumCountAggregator agg2(opentelemetry::metrics::InstrumentKind::ValueRecorder); + + agg1.update(1); + agg2.update(2); + + agg1.merge(agg2); + + // Verify that the values did NOT merge + auto value_set = agg1.get_values(); + ASSERT_EQ(value_set[0], 1); // min + ASSERT_EQ(value_set[0], 1); // max + ASSERT_EQ(value_set[0], 1); // sum + ASSERT_EQ(value_set[0], 1); // count +} + +TEST(MinMaxSumCountAggregator, Types) +{ + // This test verifies that we do not encounter any errors when + // using various numeric types. + MinMaxSumCountAggregator agg_int(opentelemetry::metrics::InstrumentKind::Counter); + MinMaxSumCountAggregator agg_long(opentelemetry::metrics::InstrumentKind::Counter); + MinMaxSumCountAggregator agg_float(opentelemetry::metrics::InstrumentKind::Counter); + MinMaxSumCountAggregator agg_double(opentelemetry::metrics::InstrumentKind::Counter); + + for (int i = 1; i <= 10; ++i) + { + agg_int.update(i); + agg_long.update(i); + } + + for (float i = 1.0; i <= 10.0; i += 1) + { + agg_float.update(i); + agg_double.update(i); + } + + auto value_set = agg_int.get_values(); + ASSERT_EQ(value_set[0], 1); // min + ASSERT_EQ(value_set[1], 10); // max + ASSERT_EQ(value_set[2], 55); // sum + ASSERT_EQ(value_set[3], 10); // count + + auto value_set2 = agg_long.get_values(); + ASSERT_EQ(value_set[0], 1); // min + ASSERT_EQ(value_set[1], 10); // max + ASSERT_EQ(value_set[2], 55); // sum + ASSERT_EQ(value_set[3], 10); // count + + auto value_set3 = agg_float.get_values(); + ASSERT_EQ(value_set[0], 1.0); // min + ASSERT_EQ(value_set[1], 10.0); // max + ASSERT_EQ(value_set[2], 55.0); // sum + ASSERT_EQ(value_set[3], 10); // count + + auto value_set4 = agg_double.get_values(); + ASSERT_EQ(value_set[0], 1.0); // min + ASSERT_EQ(value_set[1], 10.0); // max + ASSERT_EQ(value_set[2], 55.0); // sum + ASSERT_EQ(value_set[3], 10); // count +} + +static void callback(MinMaxSumCountAggregator &agg) +{ + // 1 + 2 + ... + 10000 = 50005000 + for (int i = 1; i <= 10000; ++i) + { + agg.update(i); + } +} + +TEST(MinMaxSumCountAggregator, Concurrency) +{ + // This test checks that the aggregator updates appropriately + // when called in a multi-threaded context. + MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + std::thread first(&callback, std::ref(agg)); + std::thread second(&callback, std::ref(agg)); + + first.join(); + second.join(); + + auto value_set = agg.get_values(); + ASSERT_EQ(value_set[0], 1); + ASSERT_EQ(value_set[1], 10000); + ASSERT_EQ(value_set[2], 2 * 50005000); + ASSERT_EQ(value_set[3], 2 * 10000); +} \ No newline at end of file From e73dffae5ed73d202c1d08bbba7aa7217b82885c Mon Sep 17 00:00:00 2001 From: Brandon Kimberly Date: Thu, 30 Jul 2020 11:50:00 -0400 Subject: [PATCH 15/37] Add Exact Aggregator (#198) --- .../sdk/metrics/aggregator/exact_aggregator.h | 164 +++++++++++++ sdk/test/metrics/BUILD | 11 + sdk/test/metrics/CMakeLists.txt | 2 +- sdk/test/metrics/exact_aggregator_test.cc | 217 ++++++++++++++++++ 4 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h create mode 100644 sdk/test/metrics/exact_aggregator_test.cc diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h new file mode 100644 index 0000000000..00ec1ae12d --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h @@ -0,0 +1,164 @@ +#pragma once + +#include "opentelemetry/metrics/instrument.h" +#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" +#include "opentelemetry/version.h" + +#include +#include +#include +#include + +namespace metrics_api = opentelemetry::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +/** + * This aggregator has two modes. In-order and quantile estimation. + * + * The first mode simply stores all values sent to the Update() + * function in a vector and maintains the order they were sent in. + * + * The second mode also stores all values sent to the Update() + * function in a vector but sorts this vector when Checkpoint() + * is called. This mode also includes a function, Quantile(), + * that estimates the quantiles of the recorded data. + * + * @tparam T the type of values stored in this aggregator. + */ +template +class ExactAggregator : public Aggregator +{ +public: + ExactAggregator(metrics_api::InstrumentKind kind, bool quant_estimation = false) + { + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + this->kind_ = kind; + this->checkpoint_ = this->values_; + this->agg_kind_ = AggregatorKind::Exact; + quant_estimation_ = quant_estimation; + } + + ~ExactAggregator() = default; + + ExactAggregator(const ExactAggregator &cp) + { + this->values_ = cp.values_; + this->checkpoint_ = cp.checkpoint_; + this->kind_ = cp.kind_; + this->agg_kind_ = cp.agg_kind_; + quant_estimation_ = cp.quant_estimation_; + // use default initialized mutex as they cannot be copied + } + + /** + * Receives a captured value from the instrument and adds it to the values_ vector. + * + * @param val, the raw value used in aggregation + */ + void update(T val) override + { + this->mu_.lock(); + this->values_.push_back(val); + this->mu_.unlock(); + } + + /** + * Checkpoints the current values. This function will overwrite the current checkpoint with the + * current value. Sorts the values_ vector if quant_estimation_ == true + * + */ + void checkpoint() override + { + this->mu_.lock(); + if (quant_estimation_) + { + std::sort(this->values_.begin(), this->values_.end()); + } + this->checkpoint_ = this->values_; + this->values_.clear(); + this->mu_.unlock(); + } + + /** + * Merges two exact aggregators' values_ vectors together. + * + * @param other the aggregator to merge with this aggregator + */ + void merge(const ExactAggregator &other) + { + if (this->kind_ == other.kind_) + { + this->mu_.lock(); + // First merge values + this->values_.insert(this->values_.end(), other.values_.begin(), other.values_.end()); + // Now merge checkpoints + this->checkpoint_.insert(this->checkpoint_.end(), other.checkpoint_.begin(), + other.checkpoint_.end()); + this->mu_.unlock(); + } + else + { + // Log error + return; + } + } + + /** + * Performs quantile estimation on the checkpoint vector in this aggregator. + * This function only works if quant_estimation_ == true. + * @param q the quantile to estimate. 0 <= q <= 1 + * @return the nearest value in the vector to the exact quantile. + */ + T get_quantiles(double q) override + { + if (!quant_estimation_) + { +// Log error +#if __EXCEPTIONS + throw std::domain_error("Exact aggregator is not in quantile estimation mode!"); +#else + std::terminate(); +#endif + } + if (this->checkpoint_.size() == 0 || q < 0 || q > 1) + { +// Log error +#if __EXCEPTIONS + throw std::invalid_argument("Arg 'q' must be between 0 and 1, inclusive"); +#else + std::terminate(); +#endif + } + else if (q == 0 || this->checkpoint_.size() == 1) + { + return this->checkpoint_[0]; + } + else if (q == 1) + { + return this->checkpoint_[this->checkpoint_.size() - 1]; + } + else + { + float position = float(this->checkpoint_.size() - 1) * q; + int ceiling = ceil(position); + return this->checkpoint_[ceiling]; + } + } + + //////////////////////////ACCESSOR FUNCTIONS////////////////////////// + std::vector get_checkpoint() override { return this->checkpoint_; } + + std::vector get_values() override { return this->values_; } + + bool get_quant_estimation() override { return quant_estimation_; } + +private: + bool quant_estimation_; // Used to switch between in-order and quantile estimation modes +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD index ec3ec362ab..d24acd3e58 100644 --- a/sdk/test/metrics/BUILD +++ b/sdk/test/metrics/BUILD @@ -42,6 +42,17 @@ cc_test( ], ) +cc_test( + name = "exact_aggregator_test", + srcs = [ + "exact_aggregator_test.cc", + ], + deps = [ + "//sdk/src/metrics", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "histogram_aggregator_test", srcs = [ diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index 3d906b6bcb..7ad1d9e81e 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -1,5 +1,5 @@ foreach(testname meter_provider_sdk_test gauge_aggregator_test - min_max_sum_count_aggregator_test) + min_max_sum_count_aggregator_test exact_aggregator_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics) diff --git a/sdk/test/metrics/exact_aggregator_test.cc b/sdk/test/metrics/exact_aggregator_test.cc new file mode 100644 index 0000000000..be32b87704 --- /dev/null +++ b/sdk/test/metrics/exact_aggregator_test.cc @@ -0,0 +1,217 @@ +#include +#include + +#include "opentelemetry/sdk/metrics/aggregator/exact_aggregator.h" + +using namespace opentelemetry::sdk::metrics; + +TEST(ExactAggregatorOrdered, Update) +{ + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + std::vector correct; + + ASSERT_EQ(agg.get_values(), correct); + + agg.update(1); + correct.push_back(1); + + ASSERT_EQ(agg.get_values(), std::vector{1}); + + for (int i = 2; i <= 5; ++i) + { + correct.push_back(i); + agg.update(i); + } + ASSERT_EQ(agg.get_values(), correct); +} + +TEST(ExactAggregatorOrdered, Checkpoint) +{ + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + std::vector correct; + + ASSERT_EQ(agg.get_checkpoint(), correct); + + agg.update(1); + correct.push_back(1); + agg.checkpoint(); + + ASSERT_EQ(agg.get_checkpoint(), correct); +} + +TEST(ExactAggregatorOrdered, Merge) +{ + ExactAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); + ExactAggregator agg2(opentelemetry::metrics::InstrumentKind::Counter); + + agg1.update(1); + agg2.update(2); + agg1.merge(agg2); + + std::vector correct{1, 2}; + + ASSERT_EQ(agg1.get_values(), correct); +} + +TEST(ExactAggregatorOrdered, BadMerge) +{ + // This verifies that we encounter and error when we try to merge + // two aggregators of different numeric types together. + ExactAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); + ExactAggregator agg2(opentelemetry::metrics::InstrumentKind::ValueRecorder); + + agg1.update(1); + agg2.update(2); + + agg1.merge(agg2); + + // Verify that the aggregators did NOT merge + std::vector correct{1}; + ASSERT_EQ(agg1.get_values(), correct); +} + +TEST(ExactAggregatorOrdered, Types) +{ + // This test verifies that we do not encounter any errors when + // using various numeric types. + ExactAggregator agg_int(opentelemetry::metrics::InstrumentKind::Counter); + ExactAggregator agg_long(opentelemetry::metrics::InstrumentKind::Counter); + ExactAggregator agg_float(opentelemetry::metrics::InstrumentKind::Counter); + ExactAggregator agg_double(opentelemetry::metrics::InstrumentKind::Counter); + + for (int i = 1; i <= 5; ++i) + { + agg_int.update(i); + agg_long.update(i); + } + + for (float i = 1.0; i <= 5.0; i += 1) + { + agg_float.update(i); + agg_double.update(i); + } + + std::vector correct_int{1, 2, 3, 4, 5}; + std::vector correct_long{1, 2, 3, 4, 5}; + std::vector correct_float{1.0, 2.0, 3.0, 4.0, 5.0}; + std::vector correct_double{1.0, 2.0, 3.0, 4.0, 5.0}; + + ASSERT_EQ(agg_int.get_values(), correct_int); + ASSERT_EQ(agg_long.get_values(), correct_long); + ASSERT_EQ(agg_float.get_values(), correct_float); + ASSERT_EQ(agg_double.get_values(), correct_double); +} + +TEST(ExactAggregatorQuant, Update) +{ + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); + + std::vector correct; + + ASSERT_EQ(agg.get_values(), correct); + + agg.update(1); + correct.push_back(1); + + ASSERT_EQ(agg.get_values(), std::vector{1}); + + for (int i = 2; i <= 5; ++i) + { + correct.push_back(i); + agg.update(i); + } + ASSERT_EQ(agg.get_values(), correct); +} + +TEST(ExactAggregatorQuant, Checkpoint) +{ + // This test verifies that the aggregator updates correctly when + // quantile estimation is turned on. + + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); + + std::vector correct; + + ASSERT_EQ(agg.get_checkpoint(), correct); + + agg.update(1); + agg.update(0); + agg.update(-1); + + // The vector MUST be sorted when checkpointed + correct.push_back(-1); + correct.push_back(0); + correct.push_back(1); + agg.checkpoint(); + + ASSERT_EQ(agg.get_checkpoint(), correct); +} + +TEST(ExactAggregatorQuant, Quantile) +{ + // This test verifies that the quantile estimation function returns + // the correct values. + + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); + + std::vector tmp{3, 9, 42, 57, 163, 210, 272, 300}; + for (int i : tmp) + { + agg.update(i); + } + agg.checkpoint(); + ASSERT_EQ(agg.get_quantiles(.25), 42); + ASSERT_EQ(agg.get_quantiles(0.5), 163); + ASSERT_EQ(agg.get_quantiles(0.75), 272); +} + +TEST(ExactAggregatorInOrder, Quantile) +{ + // This test verifies that if the user has an exact aggregator in "in-order" mode + // an exception will be thrown if they call the quantile() function. + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); + + std::vector tmp{3, 9, 42, 57, 163, 210, 272, 300}; + for (int i : tmp) + { + agg.update(i); + } + agg.checkpoint(); +#if __EXCEPTIONS + ASSERT_THROW(agg.get_quantiles(0.5), std::domain_error); +#else +#endif +} + +void callback(ExactAggregator &agg) +{ + for (int i = 1; i <= 10000; ++i) + { + agg.update(i); + } +} + +TEST(ExactAggregatorQuant, Concurrency) +{ + // This test checks that the aggregator updates appropriately + // when called in a multi-threaded context. + ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); + + std::thread first(&callback, std::ref(agg)); + std::thread second(&callback, std::ref(agg)); + + first.join(); + second.join(); + + std::vector correct; + for (int i = 1; i <= 10000; ++i) + { + correct.push_back(i); + correct.push_back(i); + } + agg.checkpoint(); + + ASSERT_EQ(agg.get_checkpoint(), correct); +} \ No newline at end of file From 97df5877b6d6677dd79255f36d40f98b0ec41027 Mon Sep 17 00:00:00 2001 From: Brandon Kimberly Date: Thu, 30 Jul 2020 12:34:12 -0400 Subject: [PATCH 16/37] Fix Metrics SDK CMake tests (#230) --- sdk/test/metrics/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index 7ad1d9e81e..54c39e786c 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -1,5 +1,8 @@ -foreach(testname meter_provider_sdk_test gauge_aggregator_test - min_max_sum_count_aggregator_test exact_aggregator_test) +foreach( + testname + meter_provider_sdk_test gauge_aggregator_test + min_max_sum_count_aggregator_test exact_aggregator_test + counter_aggregator_test histogram_aggregator_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics) From d24c7400b664144b0bddc313ce294fc8b5269e53 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 17:41:02 +0000 Subject: [PATCH 17/37] Send variant attributes, cleanup, resolve review comments --- .../ext/zpages/tracez_http_server.h | 33 ++++--- .../ext/zpages/zpages_http_server.h | 43 +++++---- ext/src/zpages/tracez_http_server.cc | 88 ++++++++++++++----- 3 files changed, 107 insertions(+), 57 deletions(-) diff --git a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h index 74f3c5b491..f4edc85a44 100644 --- a/ext/include/opentelemetry/ext/zpages/tracez_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/tracez_http_server.h @@ -19,7 +19,7 @@ namespace zpages { class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { public: - /* + /** * Construct the server by initializing the endpoint for querying TraceZ aggregation data and files, * along with taking ownership of the aggregator whose data is used to send data to the frontend * @param aggregator is the TraceZ Data Aggregator, which calculates aggregation info @@ -27,7 +27,7 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { * @param port is the port where the TraceZ webpages will be displayed, default being 30000 */ TracezHttpServer(std::unique_ptr &&aggregator, - std::string host = "localhost", int port = 30000) : + const std::string& host = "localhost", int port = 30000) : opentelemetry::ext::zpages::zPagesHttpServer("/tracez/get", host, port), data_aggregator_(std::move(aggregator)) { InitializeTracezEndpoint(*this); @@ -35,7 +35,7 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { }; private: - /* + /** * Set the HTTP server to use the "Serve" callback to send the appropriate data when queried * @param server, which should be an instance of this object */ @@ -43,19 +43,19 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { server[endpoint_] = Serve; } - /* + /** * Updates the stored aggregation data (aggregations_) using the data aggregator */ void UpdateAggregations(); - - /* + + /** * First updates the stored aggregations, then translates that data from a C++ map to * a JSON object * @returns JSON object of collected spans bucket counts by name */ json GetAggregations(); - /* + /** * Using the stored aggregations, finds the span group with the right name and returns * its running span data as a JSON, only grabbing the fields needed for the frontend * @param name of the span group whose running data we want @@ -63,7 +63,7 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { */ json GetRunningSpansJSON(const std::string& name); - /* + /** * Using the stored aggregations, finds the span group with the right name and returns * its error span data as a JSON, only grabbing the fields needed for the frontend * @param name of the span group whose running data we want @@ -71,20 +71,27 @@ class TracezHttpServer : public opentelemetry::ext::zpages::zPagesHttpServer { */ json GetErrorSpansJSON(const std::string& name); - /* + /** * Using the stored aggregations, finds the span group with the right name and bucket index * returning its latency span data as a JSON, only grabbing the fields needed for the frontend * @param name of the span group whose latency data we want * @param index of which latency bucket to grab from * @returns JSON representing bucket span data with the passed in name and latency range */ - json GetLatencySpansJSON(const std::string& name, const int& latency_range_index); - - /* + json GetLatencySpansJSON(const std::string& name, int latency_range_index); + + /** + * Returns attributes, which have varied types, from a span data to convert into JSON + * @param sample current span data, whose attributes we want to extract + * @returns JSON representing attributes for a given threadsafe span data + */ + json GetAttributesJSON(const opentelemetry::ext::zpages::ThreadsafeSpanData& sample); + + /** * Sets the response object with the TraceZ aggregation data based on the request endpoint * @param req is the HTTP request, which we use to figure out the response to send * @param resp is the HTTP response we want to send to the frontend, either webpage or TraceZ - * aggregation data + * aggregation data */ HTTP_SERVER_NS::HttpRequestCallback Serve{[&](HTTP_SERVER_NS::HttpRequest const& req, HTTP_SERVER_NS::HttpResponse& resp) { diff --git a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h index ca0ec06928..fa8c4bd325 100644 --- a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h @@ -15,7 +15,7 @@ namespace zpages { class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { protected: - /* + /** * Construct the server by initializing the endpoint for serving static files, which show up on the * web if the user is on the given host:port. Static files can be seen relative to the folder where the * executable was ran. @@ -30,57 +30,56 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { addListeningPort(port); }; - /* + /** * Set the HTTP server to serve static files from the root of host:port * @param server should be an instance of this object */ void InitializeFileEndpoint(zPagesHttpServer& server) { server[root_endpt_] = ServeFile; } - - /* - * Helper function tat returns query information by isolating it from the base endpoint + + /** + * Helper function that returns query information by isolating it from the base endpoint + * @param uri is the full query */ std::string GetQuery(const std::string& uri) { if (endpoint_.length() + 1 > uri.length()) return uri; return uri.substr(endpoint_.length() + 1); } - /* + /** * Helper that returns whether a str starts with pre * @param str is the string we're checking * @param pre is the prefix we're checking against */ - bool StartsWith(const std::string& str, std::string pre) { - return (pre.length() > str.length()) - ? false - : str.substr(0, pre.length()) == pre; + bool StartsWith(const std::string& str, const std::string& pre) { + str.rfind(pre, 0) == 0; } - /* + /** * Helper that returns the remaining string after the leftmost backslash * @param str is the string we're extracting from */ std::string GetAfterSlash(const std::string& str) { - const auto& backslash = str.find("/"); + std::size_t backslash = str.find("/"); if (backslash == std::string::npos || backslash == str.length()) return ""; return str.substr(backslash + 1); } - /* + /** * Helper that returns the remaining string after the leftmost backslash * @param str is the string we're extracting from */ std::string GetBeforeSlash(const std::string& str) { - const auto& backslash = str.find("/"); + std::size_t backslash = str.find("/"); if (backslash == std::string::npos || backslash == str.length()) return str; return str.substr(0, backslash); } - + const std::string endpoint_; private: - /* + /** * Return whether a file is found whose location is searched for relative to where * the executable was triggered. If the file is valid, fill result with the file data/information * required to display it on a webpage @@ -88,7 +87,7 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { * @param resulting file information, necessary for displaying them on a webpage * @returns whether a file was found and result filled with display information */ - bool FileGetSuccess (std::string filename, std::vector& result) { + bool FileGetSuccess (const std::string& filename, std::vector& result) { #ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); #endif @@ -107,12 +106,12 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { return false; }; - /* + /** * Returns the extension of a file * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(std::string filename) { + std::string GetMimeContentType(const std::string& filename) { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); auto file_type = mime_types_.find(file_ext); return (file_type != mime_types_.end()) @@ -120,7 +119,7 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; - /* + /** * Returns the standardized name of a file by removing backslashes, and * assuming index.html is the wanted file if a directory is given * @param name of the file @@ -136,7 +135,7 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { return S; } - /* + /** * Sets the response object with the correct file data based on the requested file address, * or return 404 error if a file isn't found * @param req is the HTTP request, which we use to figure out the response to send @@ -167,7 +166,7 @@ class zPagesHttpServer : public HTTP_SERVER_NS::HttpServer { }}; - // Maps file extensions to their HTTP-compatible mime file type + // Maps file extensions to their HTTP-compatible mime file type const std::unordered_map mime_types_ = { {"css", "text/css"}, {"png", "image/png"}, diff --git a/ext/src/zpages/tracez_http_server.cc b/ext/src/zpages/tracez_http_server.cc index cb3546dcf6..c18d0d59b1 100644 --- a/ext/src/zpages/tracez_http_server.cc +++ b/ext/src/zpages/tracez_http_server.cc @@ -4,13 +4,9 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace ext { namespace zpages { - void TracezHttpServer::UpdateAggregations() { - aggregated_data_ = data_aggregator_->GetAggregatedTracezData(); - } - json TracezHttpServer::GetAggregations() { - UpdateAggregations(); - auto counts = json::array(); + aggregated_data_ = data_aggregator_->GetAggregatedTracezData(); + auto counts_json = json::array(); for(const auto &aggregation_group: aggregated_data_){ const auto &buckets = aggregation_group.second; @@ -22,14 +18,14 @@ namespace zpages { latency_counts.push_back(complete_ok_counts[boundary]); } - counts.push_back({ + counts_json.push_back({ {"name", aggregation_group.first}, {"error", buckets.error_span_count}, {"running", buckets.running_span_count}, {"latency", latency_counts} }); } - return counts; + return counts_json; } json TracezHttpServer::GetRunningSpansJSON(const std::string& name) { @@ -48,12 +44,13 @@ namespace zpages { {"traceid", std::string( reinterpret_cast(sample.GetTraceId().Id().data()))}, {"start", sample.GetStartTime().time_since_epoch().count()}, + {"attributes", GetAttributesJSON(sample)}, }); } } return running_json; } - + json TracezHttpServer::GetErrorSpansJSON(const std::string& name) { auto error_json = json::array(); @@ -61,45 +58,92 @@ namespace zpages { if(grouping != aggregated_data_.end()){ const auto &error_samples = grouping->second.sample_error_spans; - for(const auto &error_sample : error_samples){ + for(const auto &sample : error_samples){ error_json.push_back({ {"spanid", std::string( - reinterpret_cast(error_sample.GetSpanId().Id().data()))}, + reinterpret_cast(sample.GetSpanId().Id().data()))}, {"parentid", std::string(reinterpret_cast( - error_sample.GetParentSpanId().Id().data()))}, + sample.GetParentSpanId().Id().data()))}, {"traceid", std::string( - reinterpret_cast(error_sample.GetTraceId().Id().data()))}, - {"start", error_sample.GetStartTime().time_since_epoch().count()}, - {"status", (unsigned short)error_sample.GetStatus()} + reinterpret_cast(sample.GetTraceId().Id().data()))}, + {"start", sample.GetStartTime().time_since_epoch().count()}, + {"status", (unsigned short)sample.GetStatus()}, + {"attributes", GetAttributesJSON(sample)}, }); } } return error_json; } - json TracezHttpServer::GetLatencySpansJSON(const std::string& name, const int& latency_range_index){ + json TracezHttpServer::GetLatencySpansJSON(const std::string& name, int latency_range_index){ auto latency_json = json::array(); auto grouping = aggregated_data_.find(name); if(grouping != aggregated_data_.end()){ const auto &latency_samples = grouping->second.sample_latency_spans[latency_range_index]; - for(const auto &latency_sample : latency_samples){ + for(const auto &sample : latency_samples){ latency_json.push_back({ {"spanid", std::string( - reinterpret_cast(latency_sample.GetSpanId().Id().data()))}, + reinterpret_cast(sample.GetSpanId().Id().data()))}, {"parentid", std::string(reinterpret_cast( - latency_sample.GetParentSpanId().Id().data()))}, + sample.GetParentSpanId().Id().data()))}, {"traceid", std::string( - reinterpret_cast(latency_sample.GetTraceId().Id().data()))}, - {"start", latency_sample.GetStartTime().time_since_epoch().count()}, - {"duration", latency_sample.GetDuration().count()}, + reinterpret_cast(sample.GetTraceId().Id().data()))}, + {"start", sample.GetStartTime().time_since_epoch().count()}, + {"duration", sample.GetDuration().count()}, + {"attributes", GetAttributesJSON(sample)}, }); } } return latency_json; } + json TracezHttpServer::GetAttributesJSON(const opentelemetry::ext::zpages::ThreadsafeSpanData& sample) { + auto attributes_json = json::object(); + for (const auto &sample_attribute : sample.GetAttributes()) { + auto& key = sample_attribute.first; + auto& val = sample_attribute.second; // SpanDataAttributeValue + + /* Convert variant types to into their nonvariant form. This is done this way because + the frontend and JSON doesn't care about type, and variant's get function only allows + const integers or literals */ + + switch(val.index()) { + case 0: + attributes_json[key] = opentelemetry::nostd::get<0>(val); + break; + case 1: + attributes_json[key] = opentelemetry::nostd::get<1>(val); + break; + case 2: + attributes_json[key] = opentelemetry::nostd::get<2>(val); + break; + case 3: + attributes_json[key] = opentelemetry::nostd::get<3>(val); + break; + case 4: + attributes_json[key] = opentelemetry::nostd::get<4>(val); + break; + case 5: + attributes_json[key] = opentelemetry::nostd::get<5>(val); + break; + case 6: + attributes_json[key] = opentelemetry::nostd::get<6>(val); + break; + case 7: + attributes_json[key] = opentelemetry::nostd::get<7>(val); + break; + case 8: + attributes_json[key] = opentelemetry::nostd::get<8>(val); + break; + case 9: + attributes_json[key] = opentelemetry::nostd::get<9>(val); + break; + } + } + return attributes_json; + } } // namespace zpages } // namespace ext From c1b7ab78c9c25c9b3c3590bf4b775b24d9fa0ad3 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 17:52:30 +0000 Subject: [PATCH 18/37] Silence bazel error, unused variable --- ext/include/opentelemetry/ext/http/server/HttpServer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/include/opentelemetry/ext/http/server/HttpServer.h b/ext/include/opentelemetry/ext/http/server/HttpServer.h index de6e93e5eb..93eaa0e8e3 100644 --- a/ext/include/opentelemetry/ext/http/server/HttpServer.h +++ b/ext/include/opentelemetry/ext/http/server/HttpServer.h @@ -736,7 +736,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), handler.first.c_str()); - auto callback = handler.second; + // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when using int result = handler.second->onHttpRequest(conn.request, conn.response); if (result != 0) { From 8d5e9d1fb32631310489a8a0246ecf7fc359512f Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 17:58:23 +0000 Subject: [PATCH 19/37] Rename file to OT naming convention --- .../opentelemetry/ext/http/server/{HttpServer.h => http_server.h} | 0 .../ext/http/server/{SocketTools.h => socket_tools.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename ext/include/opentelemetry/ext/http/server/{HttpServer.h => http_server.h} (100%) rename ext/include/opentelemetry/ext/http/server/{SocketTools.h => socket_tools.h} (100%) diff --git a/ext/include/opentelemetry/ext/http/server/HttpServer.h b/ext/include/opentelemetry/ext/http/server/http_server.h similarity index 100% rename from ext/include/opentelemetry/ext/http/server/HttpServer.h rename to ext/include/opentelemetry/ext/http/server/http_server.h diff --git a/ext/include/opentelemetry/ext/http/server/SocketTools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h similarity index 100% rename from ext/include/opentelemetry/ext/http/server/SocketTools.h rename to ext/include/opentelemetry/ext/http/server/socket_tools.h From ca5728241ccb18218fb4de5d6e39bd264a97076e Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:06:53 +0000 Subject: [PATCH 20/37] Add derived file server --- .../ext/http/server/file_http_server.h | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 ext/include/opentelemetry/ext/http/server/file_http_server.h diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h new file mode 100644 index 0000000000..c1cf7258cf --- /dev/null +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "opentelemetry/ext/http/server/HttpServer.h" + +namespace HTTP_SERVER_NS { + +class FileHttpServer : public HTTP_SERVER_NS::HttpServer { + protected: + /** + * Construct the server by initializing the endpoint for serving static files, which show up on the + * web if the user is on the given host:port. Static files can be seen relative to the folder where the + * executable was ran. + */ + FileHttpServer(const std::string& host = "127.0.0.1", int port = "3333") : HttpServer() { + std::ostringstream os; + os << host << ":" << port; + setServerName(os.str()); + addListeningPort(port); + }; + + /** + * Set the HTTP server to serve static files from the root of host:port. + * Derived HTTP servers should initialize the file endpoint AFTER they + * initialize their own, otherwise everything will be served like a file + * @param server should be an instance of this object + */ + void InitializeFileEndpoint(zPagesHttpServer& server) { + server[root_endpt_] = ServeFile; + } + + private: + /** + * Return whether a file is found whose location is searched for relative to where + * the executable was triggered. If the file is valid, fill result with the file data/information + * required to display it on a webpage + * @param name of the file to look for, + * @param resulting file information, necessary for displaying them on a webpage + * @returns whether a file was found and result filled with display information + */ + bool FileGetSuccess (const std::string& filename, std::vector& result) { + #ifdef _WIN32 + std::replace(filename.begin(), filename.end(), '/', '\\'); + #endif + std::streampos size; + std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) { + size = file.tellg(); + if (size) { + result.resize(size); + file.seekg(0, std::ios::beg); + file.read(result.data(), size); + } + file.close(); + return true; + } + return false; + }; + + /** + * Returns the extension of a file + * @param name of the file + * @returns file extension type under HTTP protocol + */ + std::string GetMimeContentType(const std::string& filename) { + std::string file_ext = filename.substr(filename.find_last_of(".") + 1); + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) + ? file_type->second + : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + }; + + /** + * Returns the standardized name of a file by removing backslashes, and + * assuming index.html is the wanted file if a directory is given + * @param name of the file + */ + std::string GetFileName(std::string S) { + if (S.back() == '/') { + auto temp = S.substr(0, S.size() - 1); + S = temp; + } + // If filename appears to be a directory, serve the hypothetical index.html file there + if (S.find(".") == std::string::npos) S += "/index.html"; + + return S; + } + + /** + * Sets the response object with the correct file data based on the requested file address, + * or return 404 error if a file isn't found + * @param req is the HTTP request, which we use to figure out the response to send + * @param resp is the HTTP response we want to send to the frontend, including file data + */ + HTTP_SERVER_NS::HttpRequestCallback ServeFile{[&](HTTP_SERVER_NS::HttpRequest const& req, + HTTP_SERVER_NS::HttpResponse& resp) { + LOG_INFO("File: %s\n", req.uri.c_str()); + auto f = GetFileName(req.uri); + auto filename = f.c_str() + 1; + + std::vector content; + if (FileGetSuccess(filename, content)) { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + return resp.code; + } + // Two additional 'special' return codes possible here: + // 0 - proceed to next handler + // -1 - immediately terminate and close connection + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + resp.body = resp.message; + return 404; + }}; + + + // Maps file extensions to their HTTP-compatible mime file type + const std::unordered_map mime_types_ = { + {"css", "text/css"}, + {"png", "image/png"}, + {"js", "text/javascript"}, + {"htm", "text/html"}, + {"html", "text/html"}, + {"json", "application/json"}, + {"txt", "text/plain"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + }; + const std::string root_endpt_ = "/"; + +}; + +} // namespace HTTP_SERVER_NS From 7e67beba397e5563e9d8e3b1ee712a3c1d70b902 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:42:09 +0000 Subject: [PATCH 21/37] Update references to new header file names --- ext/include/opentelemetry/ext/http/server/file_http_server.h | 2 +- ext/include/opentelemetry/ext/http/server/http_server.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index c1cf7258cf..a95ff594d1 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -6,7 +6,7 @@ #include #include -#include "opentelemetry/ext/http/server/HttpServer.h" +#include "opentelemetry/ext/http/server/http_server.h" namespace HTTP_SERVER_NS { diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index 93eaa0e8e3..e1a57254b2 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -18,7 +18,7 @@ #include #include -#include "SocketTools.h" +#include "socket_tools.h" #ifdef HAVE_HTTP_DEBUG # ifdef LOG_TRACE From da8d9bf19237af99a539512d8c1732e298ac91f7 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:50:25 +0000 Subject: [PATCH 22/37] Update reference --- ext/include/opentelemetry/ext/zpages/zpages_http_server.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h index 8f8403b514..82fdf5b2ed 100644 --- a/ext/include/opentelemetry/ext/zpages/zpages_http_server.h +++ b/ext/include/opentelemetry/ext/zpages/zpages_http_server.h @@ -7,7 +7,7 @@ #include #include -#include "opentelemetry/ext/http/server/HttpServer.h" +#include "opentelemetry/ext/http/server/http_server.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace ext { From e7b4385912756519822e3cb2a1c5e0166cfb86ca Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:51:50 +0000 Subject: [PATCH 23/37] Add return statement in = overload --- ext/include/opentelemetry/ext/http/server/http_server.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index e1a57254b2..83af6a7ca2 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -66,7 +66,10 @@ class HttpRequestCallback public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; }; + HttpRequestCallback &operator=(HttpRequestCallback other) { + callback = other.callback; + return *this; + }; HttpRequestCallback(CallbackFunction func) : callback(func){}; From da074f840520429fd6a267c58e647127b005d3a6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 18:52:44 +0000 Subject: [PATCH 24/37] Add return statement in = overload --- ext/include/opentelemetry/ext/http/server/http_server.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index e1a57254b2..83af6a7ca2 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -66,7 +66,10 @@ class HttpRequestCallback public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; }; + HttpRequestCallback &operator=(HttpRequestCallback other) { + callback = other.callback; + return *this; + }; HttpRequestCallback(CallbackFunction func) : callback(func){}; From 15b4178e1ae51e95e8ebe90f761e2886dc3ab82e Mon Sep 17 00:00:00 2001 From: Hudson Humphries Date: Thu, 30 Jul 2020 14:59:04 -0500 Subject: [PATCH 25/37] pass in library_name and library_version into meter (#232) --- sdk/include/opentelemetry/sdk/metrics/meter.h | 10 ++++++++++ sdk/include/opentelemetry/sdk/metrics/meter_provider.h | 3 ++- sdk/src/metrics/meter_provider.cc | 4 +++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/metrics/meter.h b/sdk/include/opentelemetry/sdk/metrics/meter.h index 6b7dc1d370..9a66adb6d9 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter.h @@ -4,6 +4,7 @@ #include "opentelemetry/version.h" #include +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -13,6 +14,15 @@ namespace metrics class Meter final : public opentelemetry::metrics::Meter, public std::enable_shared_from_this { public: + explicit Meter(std::string library_name, std::string library_version) + { + library_name_ = library_name; + library_version_ = library_version; + } + +private: + std::string library_name_; + std::string library_version_; }; } // namespace metrics } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h index 4b5821c1b5..4112d14b8f 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -5,6 +5,7 @@ #include "opentelemetry/sdk/metrics/meter.h" #include +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -17,7 +18,7 @@ class MeterProvider final : public opentelemetry::metrics::MeterProvider /** * Initialize a new meter provider */ - explicit MeterProvider() noexcept; + explicit MeterProvider(std::string library_name = "", std::string library_version = "") noexcept; opentelemetry::nostd::shared_ptr GetMeter( nostd::string_view library_name, diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index d003532a9b..7c009a7bab 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -5,7 +5,9 @@ namespace sdk { namespace metrics { -MeterProvider::MeterProvider() noexcept : meter_(new Meter) {} +MeterProvider::MeterProvider(std::string library_name, std::string library_version) noexcept + : meter_(new Meter(library_name, library_version)) +{} opentelemetry::nostd::shared_ptr MeterProvider::GetMeter( nostd::string_view library_name, From 822230c4dd7d3fe3ea0b7bab17a8652261518c58 Mon Sep 17 00:00:00 2001 From: Keshav Manghat Date: Thu, 30 Jul 2020 20:22:34 +0000 Subject: [PATCH 26/37] zPages example --- examples/zpages/zpages_example.cc | 79 ++++++++++++------------------- 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/examples/zpages/zpages_example.cc b/examples/zpages/zpages_example.cc index 0c45501f88..91391380cd 100644 --- a/examples/zpages/zpages_example.cc +++ b/examples/zpages/zpages_example.cc @@ -1,58 +1,41 @@ -#pragma once - -#include +/** + * This is a basic example for zpages that helps users get familiar with how to + * use this feature in OpenTelemetery + */ #include #include #include -#include - -#include "opentelemetry/ext/zpages/zpages.h" -using opentelemetry::core::SteadyTimestamp; -namespace nostd = opentelemetry::nostd; -using opentelemetry::v0::trace::Span; +#include "opentelemetry/ext/zpages/zpages.h" // Required file include for zpages int main(int argc, char* argv[]) { + + /** + * The following line initializes zPages and starts a webserver at + * http://localhost:30000/tracez/ where spans that are created can be viewed. + * Note that the the webserver is destroyed after the application ends execution. + */ zPages(); + auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(""); - std::vector> running_span_container; - while (1) { - std::string span_name; - std::cout << "Enter span name or CTRL C to exit: "; - std::cin >> span_name; - - char span_type; - std::cout << "Enter span type Error(E), Completed(C), Running(R)"; - std::cin >> span_type; - - if(span_type == 'R'){ - running_span_container.push_back(tracer->StartSpan(span_name)); - } - else if(span_type == 'C'){ - unsigned long long int start_time; - std::cout << "Start time in nanoseconds: "; - std::cin >> start_time; - - unsigned long long int end_time; - std::cout << "End time in nanoseconds: "; - std::cin >> end_time; - - opentelemetry::trace::StartSpanOptions start; - start.start_steady_time = SteadyTimestamp(nanoseconds(start_time)); - opentelemetry::trace::EndSpanOptions end; - end.end_steady_time = SteadyTimestamp(nanoseconds(end_time)); - tracer->StartSpan(span_name,start)->End(end); - } else { - std::string description; - int error_code = 0; - std::cout << "Enter an error code (integer between 1-16): "; - std::cin >> error_code; - if(error_code < 1 || error_code > 16) error_code = 0; - tracer->StartSpan(span_name)->SetStatus((opentelemetry::trace::CanonicalCode)error_code, - description); - } - std::cout << "\n"; + + // Create a span of each type(running, completed and error) + auto running_span = tracer->StartSpan("example span"); + tracer->StartSpan("example span")->End(); + tracer->StartSpan("example span")->SetStatus( + opentelemetry::trace::CanonicalCode::CANCELLED, "Cancelled example"); + + // Change the name of the running span and end it + running_span->UpdateName("example span2"); + running_span->End(); + + // Create another running span with a different name + auto running_span2 = tracer->StartSpan("example span2"); + + // Create a completed span every second till user stops the loop + std::cout << "Presss CTRL+C to stop...\n"; + while(true){ + std::this_thread::sleep_for(seconds(1)); + tracer->StartSpan("example span")->End(); } - std::cout << "Presss to stop...\n"; - std::cin.get(); } From 55698376a2334846a5bbe1935502d87cefc744e2 Mon Sep 17 00:00:00 2001 From: Keshav Manghat Date: Thu, 30 Jul 2020 20:34:19 +0000 Subject: [PATCH 27/37] Fixed typo --- examples/zpages/zpages_example.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/zpages/zpages_example.cc b/examples/zpages/zpages_example.cc index 91391380cd..e21dc9bb9e 100644 --- a/examples/zpages/zpages_example.cc +++ b/examples/zpages/zpages_example.cc @@ -13,7 +13,7 @@ int main(int argc, char* argv[]) { /** * The following line initializes zPages and starts a webserver at * http://localhost:30000/tracez/ where spans that are created can be viewed. - * Note that the the webserver is destroyed after the application ends execution. + * Note that the webserver is destroyed after the application ends execution. */ zPages(); From 0a35712bb3d6725f7d219a6d668a016c302f3be6 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 22:55:03 +0000 Subject: [PATCH 28/37] Run formatter --- .../ext/http/server/file_http_server.h | 129 +++++++++--------- .../ext/http/server/http_server.h | 24 ++-- 2 files changed, 73 insertions(+), 80 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index a95ff594d1..4c88f0ecb4 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -8,16 +8,19 @@ #include "opentelemetry/ext/http/server/http_server.h" -namespace HTTP_SERVER_NS { +namespace HTTP_SERVER_NS +{ -class FileHttpServer : public HTTP_SERVER_NS::HttpServer { - protected: +class FileHttpServer : public HTTP_SERVER_NS::HttpServer +{ +protected: /** - * Construct the server by initializing the endpoint for serving static files, which show up on the - * web if the user is on the given host:port. Static files can be seen relative to the folder where the - * executable was ran. + * Construct the server by initializing the endpoint for serving static files, which show up on + * the web if the user is on the given host:port. Static files can be seen relative to the folder + * where the executable was ran. */ - FileHttpServer(const std::string& host = "127.0.0.1", int port = "3333") : HttpServer() { + FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() + { std::ostringstream os; os << host << ":" << port; setServerName(os.str()); @@ -30,11 +33,9 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer& server) { - server[root_endpt_] = ServeFile; - } + void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } - private: +private: /** * Return whether a file is found whose location is searched for relative to where * the executable was triggered. If the file is valid, fill result with the file data/information @@ -43,18 +44,21 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param resulting file information, necessary for displaying them on a webpage * @returns whether a file was found and result filled with display information */ - bool FileGetSuccess (const std::string& filename, std::vector& result) { - #ifdef _WIN32 + bool FileGetSuccess(const std::string &filename, std::vector &result) + { +#ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); - #endif +#endif std::streampos size; std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) { + if (file.is_open()) + { size = file.tellg(); - if (size) { - result.resize(size); - file.seekg(0, std::ios::beg); - file.read(result.data(), size); + if (size) + { + result.resize(size); + file.seekg(0, std::ios::beg); + file.read(result.data(), size); } file.close(); return true; @@ -67,12 +71,11 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(const std::string& filename) { + std::string GetMimeContentType(const std::string &filename) + { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); - auto file_type = mime_types_.find(file_ext); - return (file_type != mime_types_.end()) - ? file_type->second - : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) ? file_type->second : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; /** @@ -80,13 +83,16 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) { - if (S.back() == '/') { + std::string GetFileName(std::string S) + { + if (S.back() == '/') + { auto temp = S.substr(0, S.size() - 1); - S = temp; + S = temp; } // If filename appears to be a directory, serve the hypothetical index.html file there - if (S.find(".") == std::string::npos) S += "/index.html"; + if (S.find(".") == std::string::npos) + S += "/index.html"; return S; } @@ -97,45 +103,38 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param req is the HTTP request, which we use to figure out the response to send * @param resp is the HTTP response we want to send to the frontend, including file data */ - HTTP_SERVER_NS::HttpRequestCallback ServeFile{[&](HTTP_SERVER_NS::HttpRequest const& req, - HTTP_SERVER_NS::HttpResponse& resp) { - LOG_INFO("File: %s\n", req.uri.c_str()); - auto f = GetFileName(req.uri); - auto filename = f.c_str() + 1; + HTTP_SERVER_NS::HttpRequestCallback ServeFile{ + [&](HTTP_SERVER_NS::HttpRequest const &req, HTTP_SERVER_NS::HttpResponse &resp) { + LOG_INFO("File: %s\n", req.uri.c_str()); + auto f = GetFileName(req.uri); + auto filename = f.c_str() + 1; - std::vector content; - if (FileGetSuccess(filename, content)) { - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); - resp.body = std::string(content.data(), content.size()); - resp.code = 200; + std::vector content; + if (FileGetSuccess(filename, content)) + { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + return resp.code; + } + // Two additional 'special' return codes possible here: + // 0 - proceed to next handler + // -1 - immediately terminate and close connection + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - return resp.code; - } - // Two additional 'special' return codes possible here: - // 0 - proceed to next handler - // -1 - immediately terminate and close connection - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; - resp.code = 404; - resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - resp.body = resp.message; - return 404; - }}; - - - // Maps file extensions to their HTTP-compatible mime file type - const std::unordered_map mime_types_ = { - {"css", "text/css"}, - {"png", "image/png"}, - {"js", "text/javascript"}, - {"htm", "text/html"}, - {"html", "text/html"}, - {"json", "application/json"}, - {"txt", "text/plain"}, - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - }; - const std::string root_endpt_ = "/"; + resp.body = resp.message; + return 404; + }}; + // Maps file extensions to their HTTP-compatible mime file type + const std::unordered_map mime_types_ = { + {"css", "text/css"}, {"png", "image/png"}, {"js", "text/javascript"}, + {"htm", "text/html"}, {"html", "text/html"}, {"json", "application/json"}, + {"txt", "text/plain"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, + }; + const std::string root_endpt_ = "/"; }; -} // namespace HTTP_SERVER_NS +} // namespace HTTP_SERVER_NS diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index 83af6a7ca2..a4cc6cc814 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -66,7 +66,8 @@ class HttpRequestCallback public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { + HttpRequestCallback &operator=(HttpRequestCallback other) + { callback = other.callback; return *this; }; @@ -145,7 +146,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback HttpRequestHandler &operator=(std::pair other) { - first = other.first; + first = other.first; second = other.second; return (*this); }; @@ -236,22 +237,16 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return m_handlers.back(); } - HttpServer &operator+=( std::pair other) + HttpServer &operator+=(std::pair other) { LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); return (*this); }; - void start() - { - m_reactor.start(); - } + void start() { m_reactor.start(); } - void stop() - { - m_reactor.stop(); - } + void stop() { m_reactor.stop(); } protected: virtual void onSocketAcceptable(SocketTools::Socket socket) override @@ -739,8 +734,9 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), handler.first.c_str()); - // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when using - int result = handler.second->onHttpRequest(conn.request, conn.response); + // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when + // using + int result = handler.second->onHttpRequest(conn.request, conn.response); if (result != 0) { conn.response.code = result; @@ -781,7 +777,6 @@ class HttpServer : private SocketTools::Reactor::SocketCallback } public: - static char const *getDefaultResponseMessage(int code) { switch (code) @@ -895,4 +890,3 @@ class HttpServer : private SocketTools::Reactor::SocketCallback }; } // namespace HTTP_SERVER_NS - From de0d4a9b37e9130aa2fe66376eeb6df346eb9f92 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 22:59:11 +0000 Subject: [PATCH 29/37] Run formatter with style=google --- .../ext/http/server/file_http_server.h | 116 ++-- .../ext/http/server/http_server.h | 533 ++++++++---------- .../ext/http/server/socket_tools.h | 476 +++++++--------- 3 files changed, 482 insertions(+), 643 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 4c88f0ecb4..2e1cfa8066 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -8,19 +8,17 @@ #include "opentelemetry/ext/http/server/http_server.h" -namespace HTTP_SERVER_NS -{ +namespace HTTP_SERVER_NS { -class FileHttpServer : public HTTP_SERVER_NS::HttpServer -{ -protected: +class FileHttpServer : public HTTP_SERVER_NS::HttpServer { + protected: /** - * Construct the server by initializing the endpoint for serving static files, which show up on - * the web if the user is on the given host:port. Static files can be seen relative to the folder - * where the executable was ran. + * Construct the server by initializing the endpoint for serving static files, + * which show up on the web if the user is on the given host:port. Static + * files can be seen relative to the folder where the executable was ran. */ - FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() - { + FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") + : HttpServer() { std::ostringstream os; os << host << ":" << port; setServerName(os.str()); @@ -33,29 +31,31 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } + void InitializeFileEndpoint(zPagesHttpServer &server) { + server[root_endpt_] = ServeFile; + } -private: + private: /** - * Return whether a file is found whose location is searched for relative to where - * the executable was triggered. If the file is valid, fill result with the file data/information - * required to display it on a webpage + * Return whether a file is found whose location is searched for relative to + * where the executable was triggered. If the file is valid, fill result with + * the file data/information required to display it on a webpage * @param name of the file to look for, - * @param resulting file information, necessary for displaying them on a webpage - * @returns whether a file was found and result filled with display information + * @param resulting file information, necessary for displaying them on a + * webpage + * @returns whether a file was found and result filled with display + * information */ - bool FileGetSuccess(const std::string &filename, std::vector &result) - { + bool FileGetSuccess(const std::string &filename, std::vector &result) { #ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); #endif std::streampos size; - std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) - { + std::ifstream file(filename, + std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) { size = file.tellg(); - if (size) - { + if (size) { result.resize(size); file.seekg(0, std::ios::beg); file.read(result.data(), size); @@ -71,11 +71,11 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(const std::string &filename) - { + std::string GetMimeContentType(const std::string &filename) { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); - auto file_type = mime_types_.find(file_ext); - return (file_type != mime_types_.end()) ? file_type->second : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) ? file_type->second + : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; /** @@ -83,56 +83,62 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) - { - if (S.back() == '/') - { + std::string GetFileName(std::string S) { + if (S.back() == '/') { auto temp = S.substr(0, S.size() - 1); - S = temp; + S = temp; } - // If filename appears to be a directory, serve the hypothetical index.html file there - if (S.find(".") == std::string::npos) - S += "/index.html"; + // If filename appears to be a directory, serve the hypothetical index.html + // file there + if (S.find(".") == std::string::npos) S += "/index.html"; return S; } /** - * Sets the response object with the correct file data based on the requested file address, - * or return 404 error if a file isn't found - * @param req is the HTTP request, which we use to figure out the response to send - * @param resp is the HTTP response we want to send to the frontend, including file data + * Sets the response object with the correct file data based on the requested + * file address, or return 404 error if a file isn't found + * @param req is the HTTP request, which we use to figure out the response to + * send + * @param resp is the HTTP response we want to send to the frontend, including + * file data */ HTTP_SERVER_NS::HttpRequestCallback ServeFile{ - [&](HTTP_SERVER_NS::HttpRequest const &req, HTTP_SERVER_NS::HttpResponse &resp) { + [&](HTTP_SERVER_NS::HttpRequest const &req, + HTTP_SERVER_NS::HttpResponse &resp) { LOG_INFO("File: %s\n", req.uri.c_str()); - auto f = GetFileName(req.uri); + auto f = GetFileName(req.uri); auto filename = f.c_str() + 1; std::vector content; - if (FileGetSuccess(filename, content)) - { - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); - resp.body = std::string(content.data(), content.size()); - resp.code = 200; - resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + if (FileGetSuccess(filename, content)) { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = + GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = + HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); return resp.code; } // Two additional 'special' return codes possible here: // 0 - proceed to next handler // -1 - immediately terminate and close connection - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; - resp.code = 404; - resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - resp.body = resp.message; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = + HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; + resp.message = + HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + resp.body = resp.message; return 404; }}; // Maps file extensions to their HTTP-compatible mime file type const std::unordered_map mime_types_ = { - {"css", "text/css"}, {"png", "image/png"}, {"js", "text/javascript"}, - {"htm", "text/html"}, {"html", "text/html"}, {"json", "application/json"}, - {"txt", "text/plain"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, + {"css", "text/css"}, {"png", "image/png"}, + {"js", "text/javascript"}, {"htm", "text/html"}, + {"html", "text/html"}, {"json", "application/json"}, + {"txt", "text/plain"}, {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, }; const std::string root_endpt_ = "/"; }; diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index a4cc6cc814..d345eb3e13 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -21,25 +21,23 @@ #include "socket_tools.h" #ifdef HAVE_HTTP_DEBUG -# ifdef LOG_TRACE -# undef LOG_TRACE -# define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) -# endif +#ifdef LOG_TRACE +#undef LOG_TRACE +#define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) +#endif #endif #ifndef HTTP_SERVER_NS -# define HTTP_SERVER_NS testing +#define HTTP_SERVER_NS testing #endif -namespace HTTP_SERVER_NS -{ +namespace HTTP_SERVER_NS { -constexpr const char *CONTENT_TYPE = "Content-Type"; +constexpr const char *CONTENT_TYPE = "Content-Type"; constexpr const char *CONTENT_TYPE_TEXT = "text/plain"; -constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; +constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; -struct HttpRequest -{ +struct HttpRequest { std::string client; std::string method; std::string uri; @@ -48,42 +46,38 @@ struct HttpRequest std::string content; }; -struct HttpResponse -{ +struct HttpResponse { int code; std::string message; std::map headers; std::string body; }; -using CallbackFunction = std::function; +using CallbackFunction = + std::function; -class HttpRequestCallback -{ -protected: +class HttpRequestCallback { + protected: CallbackFunction callback = nullptr; -public: + public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) - { + HttpRequestCallback &operator=(HttpRequestCallback other) { callback = other.callback; return *this; }; HttpRequestCallback(CallbackFunction func) : callback(func){}; - HttpRequestCallback &operator=(CallbackFunction func) - { + HttpRequestCallback &operator=(CallbackFunction func) { callback = func; return (*this); } - virtual int onHttpRequest(HttpRequest const &request, HttpResponse &response) - { - if (callback != nullptr) - { + virtual int onHttpRequest(HttpRequest const &request, + HttpResponse &response) { + if (callback != nullptr) { return callback(request, response); } return 0; @@ -97,17 +91,13 @@ class HttpRequestCallback // Out of scope: // - Performance // - Full support of RFC 7230-7237 -class HttpServer : private SocketTools::Reactor::SocketCallback -{ - -protected: - struct Connection - { +class HttpServer : private SocketTools::Reactor::SocketCallback { + protected: + struct Connection { SocketTools::Socket socket; std::string receiveBuffer; std::string sendBuffer; - enum - { + enum { Idle, ReceivingHeaders, Sending100Continue, @@ -128,37 +118,32 @@ class HttpServer : private SocketTools::Reactor::SocketCallback SocketTools::Reactor m_reactor; std::list m_listeningSockets; - class HttpRequestHandler : public std::pair - { - - public: - HttpRequestHandler(std::string key, HttpRequestCallback *value) - { - first = key; + class HttpRequestHandler + : public std::pair { + public: + HttpRequestHandler(std::string key, HttpRequestCallback *value) { + first = key; second = value; }; - HttpRequestHandler() : std::pair() - { - first = ""; + HttpRequestHandler() : std::pair() { + first = ""; second = nullptr; }; - HttpRequestHandler &operator=(std::pair other) - { - first = other.first; + HttpRequestHandler &operator=( + std::pair other) { + first = other.first; second = other.second; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback &cb) - { + HttpRequestHandler &operator=(HttpRequestCallback &cb) { second = &cb; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback *cb) - { + HttpRequestHandler &operator=(HttpRequestCallback *cb) { second = cb; return (*this); }; @@ -169,7 +154,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback std::map m_connections; size_t m_maxRequestHeadersSize, m_maxRequestContentSize; -public: + public: void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; } HttpServer() @@ -179,32 +164,28 @@ class HttpServer : private SocketTools::Reactor::SocketCallback m_maxRequestHeadersSize(8192), m_maxRequestContentSize(2 * 1024 * 1024){}; - HttpServer(std::string serverHost, int port = 30000) : HttpServer() - { + HttpServer(std::string serverHost, int port = 30000) : HttpServer() { std::ostringstream os; os << serverHost << ":" << port; setServerName(os.str()); addListeningPort(port); }; - ~HttpServer() - { - for (auto &sock : m_listeningSockets) - { + ~HttpServer() { + for (auto &sock : m_listeningSockets) { sock.close(); } } - void setRequestLimits(size_t maxRequestHeadersSize, size_t maxRequestContentSize) - { + void setRequestLimits(size_t maxRequestHeadersSize, + size_t maxRequestContentSize) { m_maxRequestHeadersSize = maxRequestHeadersSize; m_maxRequestContentSize = maxRequestContentSize; } void setServerName(std::string const &name) { m_serverHost = name; } - int addListeningPort(int port) - { + int addListeningPort(int port) { SocketTools::Socket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); socket.setNonBlocking(); socket.setReuseAddr(); @@ -221,24 +202,23 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return addr.port(); } - HttpRequestHandler &addHandler(const std::string &root, HttpRequestCallback &handler) - { + HttpRequestHandler &addHandler(const std::string &root, + HttpRequestCallback &handler) { // No thread-safety here! m_handlers.push_back({root, &handler}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpRequestHandler &operator[](const std::string &root) - { + HttpRequestHandler &operator[](const std::string &root) { // No thread-safety here! m_handlers.push_back({root, nullptr}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpServer &operator+=(std::pair other) - { + HttpServer &operator+=( + std::pair other) { LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); return (*this); @@ -248,47 +228,44 @@ class HttpServer : private SocketTools::Reactor::SocketCallback void stop() { m_reactor.stop(); } -protected: - virtual void onSocketAcceptable(SocketTools::Socket socket) override - { + protected: + virtual void onSocketAcceptable(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: accepting socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) != - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) != m_listeningSockets.end()); SocketTools::Socket csocket; SocketTools::SocketAddr caddr; - if (socket.accept(csocket, caddr)) - { + if (socket.accept(csocket, caddr)) { csocket.setNonBlocking(); - Connection &conn = m_connections[csocket]; - conn.socket = csocket; - conn.state = Connection::Idle; + Connection &conn = m_connections[csocket]; + conn.socket = csocket; + conn.state = Connection::Idle; conn.request.client = caddr.toString(); - m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | + SocketTools::Reactor::Closed); LOG_TRACE("HttpServer: [%s] accepted", conn.request.client.c_str()); } } - virtual void onSocketReadable(SocketTools::Socket socket) override - { + virtual void onSocketReadable(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: reading socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) == m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) - { + if (connIt == m_connections.end()) { return; } Connection &conn = connIt->second; char buffer[2048] = {0}; - int received = socket.recv(buffer, sizeof(buffer)); - LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), received); - if (received <= 0) - { + int received = socket.recv(buffer, sizeof(buffer)); + LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), + received); + if (received <= 0) { handleConnectionClosed(conn); return; } @@ -297,37 +274,32 @@ class HttpServer : private SocketTools::Reactor::SocketCallback handleConnection(conn); } - virtual void onSocketWritable(SocketTools::Socket socket) override - { + virtual void onSocketWritable(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: writing socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) == m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) - { + if (connIt == m_connections.end()) { return; } Connection &conn = connIt->second; - if (!sendMore(conn)) - { + if (!sendMore(conn)) { handleConnection(conn); } } - virtual void onSocketClosed(SocketTools::Socket socket) override - { + virtual void onSocketClosed(SocketTools::Socket socket) override { LOG_TRACE("HttpServer: closing socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == - m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), + socket) == m_listeningSockets.end()); auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) - { + if (connIt == m_connections.end()) { return; } Connection &conn = connIt->second; @@ -335,38 +307,35 @@ class HttpServer : private SocketTools::Reactor::SocketCallback handleConnectionClosed(conn); } - bool sendMore(Connection &conn) - { - if (conn.sendBuffer.empty()) - { + bool sendMore(Connection &conn) { + if (conn.sendBuffer.empty()) { return false; } - int sent = conn.socket.send(conn.sendBuffer.data(), static_cast(conn.sendBuffer.size())); + int sent = conn.socket.send(conn.sendBuffer.data(), + static_cast(conn.sendBuffer.size())); LOG_TRACE("HttpServer: [%s] sent %d", conn.request.client.c_str(), sent); - if (sent < 0 && conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) - { + if (sent < 0 && + conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) { return true; } conn.sendBuffer.erase(0, sent); - if (!conn.sendBuffer.empty()) - { - m_reactor.addSocket(conn.socket, - SocketTools::Reactor::Writable | SocketTools::Reactor::Closed); + if (!conn.sendBuffer.empty()) { + m_reactor.addSocket(conn.socket, SocketTools::Reactor::Writable | + SocketTools::Reactor::Closed); return true; } return false; } -protected: - void handleConnectionClosed(Connection &conn) - { + protected: + void handleConnectionClosed(Connection &conn) { LOG_TRACE("HttpServer: [%s] closed", conn.request.client.c_str()); - if (conn.state != Connection::Idle && conn.state != Connection::Closing) - { - LOG_WARN("HttpServer: [%s] connection closed unexpectedly", conn.request.client.c_str()); + if (conn.state != Connection::Idle && conn.state != Connection::Closing) { + LOG_WARN("HttpServer: [%s] connection closed unexpectedly", + conn.request.client.c_str()); } m_reactor.removeSocket(conn.socket); auto connIt = m_connections.find(conn.socket); @@ -374,47 +343,43 @@ class HttpServer : private SocketTools::Reactor::SocketCallback m_connections.erase(connIt); } - void handleConnection(Connection &conn) - { - for (;;) - { - if (conn.state == Connection::Idle) - { + void handleConnection(Connection &conn) { + for (;;) { + if (conn.state == Connection::Idle) { conn.response.code = 0; - conn.state = Connection::ReceivingHeaders; - LOG_TRACE("HttpServer: [%s] receiving headers", conn.request.client.c_str()); + conn.state = Connection::ReceivingHeaders; + LOG_TRACE("HttpServer: [%s] receiving headers", + conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingHeaders) - { + if (conn.state == Connection::ReceivingHeaders) { bool lfOnly = false; - size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); - if (ofs == std::string::npos) - { + size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); + if (ofs == std::string::npos) { lfOnly = true; - ofs = conn.receiveBuffer.find("\n\n"); + ofs = conn.receiveBuffer.find("\n\n"); } - size_t headersLen = (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); - if (headersLen > m_maxRequestHeadersSize) - { - LOG_WARN("HttpServer: [%s] headers too long - %u", conn.request.client.c_str(), + size_t headersLen = + (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); + if (headersLen > m_maxRequestHeadersSize) { + LOG_WARN("HttpServer: [%s] headers too long - %u", + conn.request.client.c_str(), static_cast(headersLen)); conn.response.code = 431; // Request Header Fields Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } - if (ofs == std::string::npos) - { + if (ofs == std::string::npos) { return; } - if (!parseHeaders(conn)) - { - LOG_WARN("HttpServer: [%s] invalid headers", conn.request.client.c_str()); + if (!parseHeaders(conn)) { + LOG_WARN("HttpServer: [%s] invalid headers", + conn.request.client.c_str()); conn.response.code = 400; // Bad Request - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } LOG_INFO("HttpServer: [%s] %s %s %s", conn.request.client.c_str(), @@ -422,146 +387,128 @@ class HttpServer : private SocketTools::Reactor::SocketCallback conn.request.protocol.c_str()); conn.receiveBuffer.erase(0, ofs + (lfOnly ? 2 : 4)); - conn.keepalive = (conn.request.protocol == "HTTP/1.1"); + conn.keepalive = (conn.request.protocol == "HTTP/1.1"); auto const connection = conn.request.headers.find("Connection"); - if (connection != conn.request.headers.end()) - { - if (equalsLowercased(connection->second, "keep-alive")) - { + if (connection != conn.request.headers.end()) { + if (equalsLowercased(connection->second, "keep-alive")) { conn.keepalive = true; - } - else if (equalsLowercased(connection->second, "close")) - { + } else if (equalsLowercased(connection->second, "close")) { conn.keepalive = false; } } auto const contentLength = conn.request.headers.find("Content-Length"); - if (contentLength != conn.request.headers.end()) - { + if (contentLength != conn.request.headers.end()) { conn.contentLength = atoi(contentLength->second.c_str()); - } - else - { + } else { conn.contentLength = 0; } - if (conn.contentLength > m_maxRequestContentSize) - { - LOG_WARN("HttpServer: [%s] content too long - %u", conn.request.client.c_str(), + if (conn.contentLength > m_maxRequestContentSize) { + LOG_WARN("HttpServer: [%s] content too long - %u", + conn.request.client.c_str(), static_cast(conn.contentLength)); conn.response.code = 413; // Payload Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } auto const expect = conn.request.headers.find("Expect"); - if (expect != conn.request.headers.end() && conn.request.protocol == "HTTP/1.1") - { - if (!equalsLowercased(expect->second, "100-continue")) - { - LOG_WARN("HttpServer: [%s] unknown expectation - %s", conn.request.client.c_str(), - expect->second.c_str()); + if (expect != conn.request.headers.end() && + conn.request.protocol == "HTTP/1.1") { + if (!equalsLowercased(expect->second, "100-continue")) { + LOG_WARN("HttpServer: [%s] unknown expectation - %s", + conn.request.client.c_str(), expect->second.c_str()); conn.response.code = 417; // Expectation Failed - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } conn.sendBuffer = "HTTP/1.1 100 Continue\r\n\r\n"; - conn.state = Connection::Sending100Continue; - LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", conn.request.client.c_str()); + conn.state = Connection::Sending100Continue; + LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", + conn.request.client.c_str()); continue; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", + conn.request.client.c_str()); } - if (conn.state == Connection::Sending100Continue) - { - if (sendMore(conn)) - { + if (conn.state == Connection::Sending100Continue) { + if (sendMore(conn)) { return; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", + conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingBody) - { - if (conn.receiveBuffer.length() < conn.contentLength) - { + if (conn.state == Connection::ReceivingBody) { + if (conn.receiveBuffer.length() < conn.contentLength) { return; } - if (conn.receiveBuffer.length() == conn.contentLength) - { + if (conn.receiveBuffer.length() == conn.contentLength) { conn.request.content = std::move(conn.receiveBuffer); conn.receiveBuffer.clear(); - } - else - { - conn.request.content.assign(conn.receiveBuffer, 0, conn.contentLength); + } else { + conn.request.content.assign(conn.receiveBuffer, 0, + conn.contentLength); conn.receiveBuffer.erase(0, conn.contentLength); } conn.state = Connection::Processing; - LOG_TRACE("HttpServer: [%s] processing request", conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] processing request", + conn.request.client.c_str()); } - if (conn.state == Connection::Processing) - { + if (conn.state == Connection::Processing) { processRequest(conn); std::ostringstream os; - os << conn.request.protocol << ' ' << conn.response.code << ' ' << conn.response.message - << "\r\n"; - for (auto const &header : conn.response.headers) - { + os << conn.request.protocol << ' ' << conn.response.code << ' ' + << conn.response.message << "\r\n"; + for (auto const &header : conn.response.headers) { os << header.first << ": " << header.second << "\r\n"; } os << "\r\n"; conn.sendBuffer = os.str(); - conn.state = Connection::SendingHeaders; - LOG_TRACE("HttpServer: [%s] sending headers", conn.request.client.c_str()); + conn.state = Connection::SendingHeaders; + LOG_TRACE("HttpServer: [%s] sending headers", + conn.request.client.c_str()); } - if (conn.state == Connection::SendingHeaders) - { - if (sendMore(conn)) - { + if (conn.state == Connection::SendingHeaders) { + if (sendMore(conn)) { return; } conn.sendBuffer = std::move(conn.response.body); - conn.state = Connection::SendingBody; + conn.state = Connection::SendingBody; LOG_TRACE("HttpServer: [%s] sending body", conn.request.client.c_str()); } - if (conn.state == Connection::SendingBody) - { - if (sendMore(conn)) - { + if (conn.state == Connection::SendingBody) { + if (sendMore(conn)) { return; } conn.keepalive &= allowKeepalive; - if (conn.keepalive) - { - m_reactor.addSocket(conn.socket, - SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); + if (conn.keepalive) { + m_reactor.addSocket(conn.socket, SocketTools::Reactor::Readable | + SocketTools::Reactor::Closed); conn.state = Connection::Idle; - LOG_TRACE("HttpServer: [%s] idle (keep-alive)", conn.request.client.c_str()); - if (conn.receiveBuffer.empty()) - { + LOG_TRACE("HttpServer: [%s] idle (keep-alive)", + conn.request.client.c_str()); + if (conn.receiveBuffer.empty()) { return; } - } - else - { + } else { conn.socket.shutdown(SocketTools::Socket::ShutdownSend); m_reactor.addSocket(conn.socket, SocketTools::Reactor::Closed); conn.state = Connection::Closing; @@ -569,114 +516,94 @@ class HttpServer : private SocketTools::Reactor::SocketCallback } } - if (conn.state == Connection::Closing) - { + if (conn.state == Connection::Closing) { return; } } } - bool parseHeaders(Connection &conn) - { + bool parseHeaders(Connection &conn) { // Method char const *begin = conn.receiveBuffer.c_str(); - char const *ptr = begin; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + char const *ptr = begin; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } - if (*ptr != ' ') - { + if (*ptr != ' ') { return false; } conn.request.method.assign(begin, ptr); - while (*ptr == ' ') - { + while (*ptr == ' ') { ptr++; } // URI begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } - if (*ptr != ' ') - { + if (*ptr != ' ') { return false; } conn.request.uri.assign(begin, ptr); - while (*ptr == ' ') - { + while (*ptr == ' ') { ptr++; } // Protocol begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } - if (*ptr != '\r' && *ptr != '\n') - { + if (*ptr != '\r' && *ptr != '\n') { return false; } conn.request.protocol.assign(begin, ptr); - if (*ptr == '\r') - { + if (*ptr == '\r') { ptr++; } - if (*ptr != '\n') - { + if (*ptr != '\n') { return false; } ptr++; // Headers conn.request.headers.clear(); - while (*ptr != '\r' && *ptr != '\n') - { + while (*ptr != '\r' && *ptr != '\n') { // Name begin = ptr; - while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && + *ptr != '\n') { ptr++; } - if (*ptr != ':') - { + if (*ptr != ':') { return false; } std::string name = normalizeHeaderName(begin, ptr); ptr++; - while (*ptr == ' ') - { + while (*ptr == ' ') { ptr++; } // Value begin = ptr; - while (*ptr && *ptr != '\r' && *ptr != '\n') - { + while (*ptr && *ptr != '\r' && *ptr != '\n') { ptr++; } conn.request.headers[name] = std::string(begin, ptr); - if (*ptr == '\r') - { + if (*ptr == '\r') { ptr++; } - if (*ptr != '\n') - { + if (*ptr != '\n') { return false; } ptr++; } - if (*ptr == '\r') - { + if (*ptr == '\r') { ptr++; } - if (*ptr != '\n') - { + if (*ptr != '\n') { return false; } ptr++; @@ -684,87 +611,75 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return true; } - static bool equalsLowercased(std::string const &str, char const *mask) - { + static bool equalsLowercased(std::string const &str, char const *mask) { char const *ptr = str.c_str(); - while (*ptr && *mask && ::tolower(*ptr) == *mask) - { + while (*ptr && *mask && ::tolower(*ptr) == *mask) { ptr++; mask++; } return !*ptr && !*mask; } - static std::string normalizeHeaderName(char const *begin, char const *end) - { + static std::string normalizeHeaderName(char const *begin, char const *end) { std::string result(begin, end); bool first = true; - for (char &ch : result) - { - if (first) - { - ch = static_cast(::toupper(ch)); + for (char &ch : result) { + if (first) { + ch = static_cast(::toupper(ch)); first = false; - } - else if (ch == '-') - { + } else if (ch == '-') { first = true; - } - else - { + } else { ch = static_cast(::tolower(ch)); } } return result; } - void processRequest(Connection &conn) - { + void processRequest(Connection &conn) { conn.response.message.clear(); conn.response.headers.clear(); conn.response.body.clear(); - if (conn.response.code == 0) - { + if (conn.response.code == 0) { conn.response.code = 404; // Not Found - for (auto &handler : m_handlers) - { + for (auto &handler : m_handlers) { if (conn.request.uri.length() >= handler.first.length() && - strncmp(conn.request.uri.c_str(), handler.first.c_str(), handler.first.length()) == 0) - { - LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), - handler.first.c_str()); - // auto callback = handler.second; // Bazel gets mad at this unused var, uncomment when - // using - int result = handler.second->onHttpRequest(conn.request, conn.response); - if (result != 0) - { + strncmp(conn.request.uri.c_str(), handler.first.c_str(), + handler.first.length()) == 0) { + LOG_TRACE("HttpServer: [%s] using handler for %s", + conn.request.client.c_str(), handler.first.c_str()); + // auto callback = handler.second; // Bazel gets mad at this unused + // var, uncomment when using + int result = + handler.second->onHttpRequest(conn.request, conn.response); + if (result != 0) { conn.response.code = result; break; } } } - if (conn.response.code == -1) - { - LOG_TRACE("HttpServer: [%s] closing by request", conn.request.client.c_str()); + if (conn.response.code == -1) { + LOG_TRACE("HttpServer: [%s] closing by request", + conn.request.client.c_str()); handleConnectionClosed(conn); } } - if (conn.response.message.empty()) - { + if (conn.response.message.empty()) { conn.response.message = getDefaultResponseMessage(conn.response.code); } - conn.response.headers["Host"] = m_serverHost; - conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); - conn.response.headers["Date"] = formatTimestamp(time(nullptr)); - conn.response.headers["Content-Length"] = std::to_string(conn.response.body.size()); + conn.response.headers["Host"] = m_serverHost; + conn.response.headers["Connection"] = + (conn.keepalive ? "keep-alive" : "close"); + conn.response.headers["Date"] = formatTimestamp(time(nullptr)); + conn.response.headers["Content-Length"] = + std::to_string(conn.response.body.size()); } - static std::string formatTimestamp(time_t time) - { + static std::string formatTimestamp(time_t time) { tm tm; #ifdef _WIN32 gmtime_s(&tm, &time); @@ -776,11 +691,9 @@ class HttpServer : private SocketTools::Reactor::SocketCallback return buf; } -public: - static char const *getDefaultResponseMessage(int code) - { - switch (code) - { + public: + static char const *getDefaultResponseMessage(int code) { + switch (code) { // *INDENT-OFF* case 100: return "Continue"; diff --git a/ext/include/opentelemetry/ext/http/server/socket_tools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h index 1cdc8a6881..0d9c8667ab 100644 --- a/ext/include/opentelemetry/ext/http/server/socket_tools.h +++ b/ext/include/opentelemetry/ext/http/server/socket_tools.h @@ -28,73 +28,70 @@ //# include -# include +#include // TODO: consider NOMINMAX -# undef min -# undef max -# pragma comment(lib, "ws2_32.lib") +#undef min +#undef max +#pragma comment(lib, "ws2_32.lib") #else -# include +#include -# ifdef __linux__ -# include -# endif +#ifdef __linux__ +#include +#endif -# if __APPLE__ -# include "TargetConditionals.h" +#if __APPLE__ +#include "TargetConditionals.h" // Use kqueue on mac -# include -# include -# include -# endif +#include +#include +#include +#endif // Common POSIX headers for Linux and Mac OS X -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include #endif #ifndef _Out_cap_ -# define _Out_cap_(size) +#define _Out_cap_(size) #endif #if defined(HAVE_CONSOLE_LOG) && !defined(LOG_DEBUG) // Log to console if there's no standard log facility defined -# include -# ifndef LOG_DEBUG -# define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -# endif +#include +#ifndef LOG_DEBUG +#define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +#endif #endif #ifndef LOG_DEBUG // Don't log anything if there's no standard log facility defined -# define LOG_DEBUG(fmt_, ...) -# define LOG_TRACE(fmt_, ...) -# define LOG_INFO(fmt_, ...) -# define LOG_WARN(fmt_, ...) -# define LOG_ERROR(fmt_, ...) +#define LOG_DEBUG(fmt_, ...) +#define LOG_TRACE(fmt_, ...) +#define LOG_INFO(fmt_, ...) +#define LOG_WARN(fmt_, ...) +#define LOG_ERROR(fmt_, ...) #endif -namespace common -{ +namespace common { /// /// A simple thread, derived class overloads onThread() method. /// -struct Thread -{ - +struct Thread { std::thread m_thread; volatile bool m_terminate{false}; @@ -108,20 +105,17 @@ struct Thread /// /// Start Thread /// - void startThread() - { + void startThread() { m_terminate = false; - m_thread = std::thread([&]() { this->onThread(); }); + m_thread = std::thread([&]() { this->onThread(); }); } /// /// Join Thread /// - void joinThread() - { + void joinThread() { m_terminate = true; - if (m_thread.joinable()) - { + if (m_thread.joinable()) { m_thread.join(); } } @@ -145,17 +139,13 @@ struct Thread }; }; // namespace common -namespace SocketTools -{ +namespace SocketTools { #ifdef _WIN32 // WinSocks need extra (de)initialization, solved by a global object here, // whose constructor/destructor will be called before and after main(). -struct WsaInitializer -{ - - WsaInitializer() - { +struct WsaInitializer { + WsaInitializer() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); } @@ -170,8 +160,7 @@ static WsaInitializer g_wsaInitializer; /// /// Encapsulation of sockaddr(_in) /// -struct SocketAddr -{ +struct SocketAddr { static u_long const Loopback = 0x7F000001; sockaddr m_data; @@ -182,39 +171,33 @@ struct SocketAddr /// SocketAddr SocketAddr() { memset(&m_data, 0, sizeof(m_data)); } - SocketAddr(u_long addr, int port) - { - sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - inet4.sin_port = htons(static_cast(port)); + SocketAddr(u_long addr, int port) { + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(static_cast(port)); inet4.sin_addr.s_addr = htonl(addr); } - SocketAddr(char const *addr) - { + SocketAddr(char const *addr) { #ifdef _WIN32 INT addrlen = sizeof(m_data); WCHAR buf[200]; - for (int i = 0; i < sizeof(buf) && addr[i]; i++) - { + for (int i = 0; i < sizeof(buf) && addr[i]; i++) { buf[i] = addr[i]; } buf[199] = L'\0'; ::WSAStringToAddressW(buf, AF_INET, nullptr, &m_data, &addrlen); #else sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - char const *colon = strchr(addr, ':'); - if (colon) - { + inet4.sin_family = AF_INET; + char const *colon = strchr(addr, ':'); + if (colon) { inet4.sin_port = htons(atoi(colon + 1)); char buf[16]; memcpy(buf, addr, std::min(15, colon - addr)); buf[15] = '\0'; ::inet_pton(AF_INET, buf, &inet4.sin_addr); - } - else - { + } else { inet4.sin_port = 0; ::inet_pton(AF_INET, addr, &inet4.sin_addr); } @@ -229,12 +212,11 @@ struct SocketAddr operator const sockaddr *() const { return &m_data; } - int port() const - { - switch (m_data.sa_family) - { + int port() const { + switch (m_data.sa_family) { case AF_INET: { - sockaddr_in const &inet4 = reinterpret_cast(m_data); + sockaddr_in const &inet4 = + reinterpret_cast(m_data); return ntohs(inet4.sin_port); } @@ -243,17 +225,16 @@ struct SocketAddr } } - std::string toString() const - { + std::string toString() const { std::ostringstream os; - switch (m_data.sa_family) - { + switch (m_data.sa_family) { case AF_INET: { - sockaddr_in const &inet4 = reinterpret_cast(m_data); - u_long addr = ntohl(inet4.sin_addr.s_addr); - os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.' - << (addr & 255); + sockaddr_in const &inet4 = + reinterpret_cast(m_data); + u_long addr = ntohl(inet4.sin_addr.s_addr); + os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' + << ((addr >> 8) & 255) << '.' << (addr & 255); os << ':' << ntohs(inet4.sin_port); break; } @@ -268,9 +249,7 @@ struct SocketAddr /// /// Encapsulation of a socket (non-exclusive ownership) /// -struct Socket -{ - +struct Socket { #ifdef _WIN32 typedef SOCKET Type; static Type const Invalid = INVALID_SOCKET; @@ -289,16 +268,19 @@ struct Socket operator Socket::Type() const { return m_sock; } - bool operator==(Socket const &other) const { return (m_sock == other.m_sock); } + bool operator==(Socket const &other) const { + return (m_sock == other.m_sock); + } - bool operator!=(Socket const &other) const { return (m_sock != other.m_sock); } + bool operator!=(Socket const &other) const { + return (m_sock != other.m_sock); + } bool operator<(Socket const &other) const { return (m_sock < other.m_sock); } bool invalid() const { return (m_sock == Invalid); } - void setNonBlocking() - { + void setNonBlocking() { assert(m_sock != Invalid); #ifdef _WIN32 u_long value = 1; @@ -309,38 +291,34 @@ struct Socket #endif } - bool setReuseAddr() - { + bool setReuseAddr() { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), - sizeof(value)) == 0); + return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&value), sizeof(value)) == 0); } - bool setNoDelay() - { + bool setNoDelay() { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&value), - sizeof(value)) == 0); + return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&value), sizeof(value)) == 0); } - bool connect(SocketAddr const &addr) - { + bool connect(SocketAddr const &addr) { assert(m_sock != Invalid); return (::connect(m_sock, addr, sizeof(addr)) == 0); } - void close() - { + void close() { assert(m_sock != Invalid); #ifdef _WIN32 ::closesocket(m_sock); @@ -350,27 +328,25 @@ struct Socket m_sock = Invalid; } - int recv(_Out_cap_(size) void *buffer, unsigned size) - { + int recv(_Out_cap_(size) void *buffer, unsigned size) { assert(m_sock != Invalid); int flags = 0; - return static_cast(::recv(m_sock, reinterpret_cast(buffer), size, flags)); + return static_cast( + ::recv(m_sock, reinterpret_cast(buffer), size, flags)); } - int send(void const *buffer, unsigned size) - { + int send(void const *buffer, unsigned size) { assert(m_sock != Invalid); - return static_cast(::send(m_sock, reinterpret_cast(buffer), size, 0)); + return static_cast( + ::send(m_sock, reinterpret_cast(buffer), size, 0)); } - bool bind(SocketAddr const &addr) - { + bool bind(SocketAddr const &addr) { assert(m_sock != Invalid); return (::bind(m_sock, addr, sizeof(addr)) == 0); } - bool getsockname(SocketAddr &addr) const - { + bool getsockname(SocketAddr &addr) const { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(addr); @@ -380,14 +356,12 @@ struct Socket return (::getsockname(m_sock, addr, &addrlen) == 0); } - bool listen(int backlog) - { + bool listen(int backlog) { assert(m_sock != Invalid); return (::listen(m_sock, backlog) == 0); } - bool accept(Socket &csock, SocketAddr &caddr) - { + bool accept(Socket &csock, SocketAddr &caddr) { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(caddr); @@ -398,14 +372,12 @@ struct Socket return !csock.invalid(); } - bool shutdown(int how) - { + bool shutdown(int how) { assert(m_sock != Invalid); return (::shutdown(m_sock, how) == 0); } - int error() const - { + int error() const { #ifdef _WIN32 return ::WSAGetLastError(); #else @@ -413,8 +385,7 @@ struct Socket #endif } - enum - { + enum { #ifdef _WIN32 ErrorWouldBlock = WSAEWOULDBLOCK #else @@ -422,16 +393,15 @@ struct Socket #endif }; - enum - { + enum { #ifdef _WIN32 ShutdownReceive = SD_RECEIVE, - ShutdownSend = SD_SEND, - ShutdownBoth = SD_BOTH + ShutdownSend = SD_SEND, + ShutdownBoth = SD_BOTH #else ShutdownReceive = SHUT_RD, - ShutdownSend = SHUT_WR, - ShutdownBoth = SHUT_RDWR + ShutdownSend = SHUT_WR, + ShutdownBoth = SHUT_RDWR #endif }; }; @@ -439,8 +409,7 @@ struct Socket /// /// Socket Data /// -struct SocketData -{ +struct SocketData { Socket socket; int flags; @@ -452,31 +421,22 @@ struct SocketData /// /// Socket Reactor /// -struct Reactor : protected common::Thread -{ - +struct Reactor : protected common::Thread { /// /// Socket State callback /// - class SocketCallback - { - public: - virtual void onSocketReadable(Socket sock) = 0; - virtual void onSocketWritable(Socket sock) = 0; + class SocketCallback { + public: + virtual void onSocketReadable(Socket sock) = 0; + virtual void onSocketWritable(Socket sock) = 0; virtual void onSocketAcceptable(Socket sock) = 0; - virtual void onSocketClosed(Socket sock) = 0; + virtual void onSocketClosed(Socket sock) = 0; }; /// /// Socket State /// - enum State - { - Readable = 1, - Writable = 2, - Acceptable = 4, - Closed = 8 - }; + enum State { Readable = 1, Writable = 2, Acceptable = 4, Closed = 8 }; SocketCallback &m_callback; @@ -494,20 +454,19 @@ struct Reactor : protected common::Thread #ifdef TARGET_OS_MAC /* use kqueue on Mac */ -# define KQUEUE_SIZE 32 +#define KQUEUE_SIZE 32 int kq{0}; struct kevent m_events[KQUEUE_SIZE]; #endif -public: - Reactor(SocketCallback &callback) : m_callback(callback) - { + public: + Reactor(SocketCallback &callback) : m_callback(callback) { #ifdef __linux__ -# ifdef ANDROID +#ifdef ANDROID m_epollFd = ::epoll_create(0); -# else +#else m_epollFd = ::epoll_create1(0); -# endif +#endif #endif #ifdef TARGET_OS_MAC @@ -516,8 +475,7 @@ struct Reactor : protected common::Thread #endif } - ~Reactor() - { + ~Reactor() { #ifdef __linux__ ::close(m_epollFd); #endif @@ -531,25 +489,21 @@ struct Reactor : protected common::Thread /// /// /// - void addSocket(const Socket &socket, int flags) - { - if (flags == 0) - { + void addSocket(const Socket &socket, int flags) { + if (flags == 0) { removeSocket(socket); - } - else - { + } else { auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it == m_sockets.end()) - { - LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", static_cast(socket), flags); + if (it == m_sockets.end()) { + LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", + static_cast(socket), flags); #ifdef _WIN32 m_events.push_back(::WSACreateEvent()); #endif #ifdef __linux__ epoll_event event = {}; - event.data.fd = socket; - event.events = 0; + event.data.fd = socket; + event.events = 0; ::epoll_ctl(m_epollFd, EPOLL_CTL_ADD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -563,33 +517,27 @@ struct Reactor : protected common::Thread #endif m_sockets.push_back(SocketData()); m_sockets.back().socket = socket; - m_sockets.back().flags = 0; - it = m_sockets.end() - 1; - } - else - { - LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", static_cast(socket), flags); + m_sockets.back().flags = 0; + it = m_sockets.end() - 1; + } else { + LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", + static_cast(socket), flags); } - if (it->flags != flags) - { + if (it->flags != flags) { it->flags = flags; #ifdef _WIN32 long lNetworkEvents = 0; - if (it->flags & Readable) - { + if (it->flags & Readable) { lNetworkEvents |= FD_READ; } - if (it->flags & Writable) - { + if (it->flags & Writable) { lNetworkEvents |= FD_WRITE; } - if (it->flags & Acceptable) - { + if (it->flags & Acceptable) { lNetworkEvents |= FD_ACCEPT; } - if (it->flags & Closed) - { + if (it->flags & Closed) { lNetworkEvents |= FD_CLOSE; } auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); @@ -597,22 +545,19 @@ struct Reactor : protected common::Thread #endif #ifdef __linux__ int events = 0; - if (it->flags & Readable) - { + if (it->flags & Readable) { events |= EPOLLIN; } - if (it->flags & Writable) - { + if (it->flags & Writable) { events |= EPOLLOUT; } - if (it->flags & Acceptable) - { + if (it->flags & Acceptable) { events |= EPOLLIN; } // if (it->flags & Closed) - always handled (EPOLLERR | EPOLLHUP) epoll_event event = {}; - event.data.fd = socket; - event.events = events; + event.data.fd = socket; + event.events = events; ::epoll_ctl(m_epollFd, EPOLL_CTL_MOD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -626,12 +571,10 @@ struct Reactor : protected common::Thread /// Remove Socket /// /// - void removeSocket(const Socket &socket) - { + void removeSocket(const Socket &socket) { LOG_TRACE("Reactor: Removing socket 0x%x", static_cast(socket)); auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it != m_sockets.end()) - { + if (it != m_sockets.end()) { #ifdef _WIN32 auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); ::WSAEventSelect(it->socket, *eventIt, 0); @@ -646,14 +589,12 @@ struct Reactor : protected common::Thread bzero(&event, sizeof(event)); event.ident = socket; EV_SET(&event, socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } @@ -665,8 +606,7 @@ struct Reactor : protected common::Thread /// /// Start server /// - void start() - { + void start() { LOG_INFO("Reactor: Starting..."); startThread(); } @@ -674,36 +614,31 @@ struct Reactor : protected common::Thread /// /// Stop server /// - void stop() - { + void stop() { LOG_INFO("Reactor: Stopping..."); joinThread(); #ifdef _WIN32 - for (auto &hEvent : m_events) - { + for (auto &hEvent : m_events) { ::WSACloseEvent(hEvent); } #else /* Linux and Mac */ - for (auto &sd : m_sockets) - { -# ifdef __linux__ + for (auto &sd : m_sockets) { +#ifdef __linux__ ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, sd.socket, nullptr); -# endif -# ifdef TARGET_OS_MAC +#endif +#ifdef TARGET_OS_MAC struct kevent event; bzero(&event, sizeof(event)); event.ident = sd.socket; EV_SET(&event, sd.socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, sd.socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } -# endif +#endif } #endif m_sockets.clear(); @@ -712,80 +647,74 @@ struct Reactor : protected common::Thread /// /// Thread Loop for async events processing /// - virtual void onThread() override - { + virtual void onThread() override { LOG_INFO("Reactor: Thread started"); - while (!shouldTerminate()) - { + while (!shouldTerminate()) { #ifdef _WIN32 - DWORD dwResult = ::WSAWaitForMultipleEvents(static_cast(m_events.size()), - m_events.data(), FALSE, 500, FALSE); - if (dwResult == WSA_WAIT_TIMEOUT) - { + DWORD dwResult = + ::WSAWaitForMultipleEvents(static_cast(m_events.size()), + m_events.data(), FALSE, 500, FALSE); + if (dwResult == WSA_WAIT_TIMEOUT) { continue; } assert(dwResult <= WSA_WAIT_EVENT_0 + m_events.size()); - int index = dwResult - WSA_WAIT_EVENT_0; + int index = dwResult - WSA_WAIT_EVENT_0; Socket socket = m_sockets[index].socket; - int flags = m_sockets[index].flags; + int flags = m_sockets[index].flags; WSANETWORKEVENTS ne; ::WSAEnumNetworkEvents(socket, m_events[index], &ne); - LOG_TRACE("Reactor: Handling socket 0x%x (index %d) with active flags 0x%x (armed 0x%x)", - static_cast(socket), index, ne.lNetworkEvents, flags); + LOG_TRACE( + "Reactor: Handling socket 0x%x (index %d) with active flags 0x%x " + "(armed 0x%x)", + static_cast(socket), index, ne.lNetworkEvents, flags); - if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) - { + if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) - { + if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) - { + if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) - { + if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) { m_callback.onSocketClosed(socket); } #endif #ifdef __linux__ epoll_event events[4]; - int result = ::epoll_wait(m_epollFd, events, sizeof(events) / sizeof(events[0]), 500); - if (result == 0 || (result == -1 && errno == EINTR)) - { + int result = ::epoll_wait(m_epollFd, events, + sizeof(events) / sizeof(events[0]), 500); + if (result == 0 || (result == -1 && errno == EINTR)) { continue; } - assert(result >= 1 && static_cast(result) <= sizeof(events) / sizeof(events[0])); - for (int i = 0; i < result; i++) - { - auto it = std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); + assert(result >= 1 && + static_cast(result) <= sizeof(events) / sizeof(events[0])); + for (int i = 0; i < result; i++) { + auto it = + std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE("Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", - static_cast(socket), events[i].events, flags); + LOG_TRACE( + "Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), events[i].events, flags); - if ((flags & Readable) && (events[i].events & EPOLLIN)) - { + if ((flags & Readable) && (events[i].events & EPOLLIN)) { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (events[i].events & EPOLLOUT)) - { + if ((flags & Writable) && (events[i].events & EPOLLOUT)) { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (events[i].events & EPOLLIN)) - { + if ((flags & Acceptable) && (events[i].events & EPOLLIN)) { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) - { + if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) { m_callback.onSocketClosed(socket); } } @@ -794,58 +723,49 @@ struct Reactor : protected common::Thread #if defined(TARGET_OS_MAC) unsigned waitms = 500; // never block for more than 500ms struct timespec timeout; - timeout.tv_sec = waitms / 1000; + timeout.tv_sec = waitms / 1000; timeout.tv_nsec = (waitms % 1000) * 1000 * 1000; int nev = kevent(kq, NULL, 0, m_events, KQUEUE_SIZE, &timeout); - for (int i = 0; i < nev; i++) - { + for (int i = 0; i < nev; i++) { struct kevent &event = m_events[i]; - int fd = (int)event.ident; - auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); + int fd = (int)event.ident; + auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", static_cast(socket), - event.flags, event.fflags); + LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), event.flags, event.fflags); - if (event.filter == EVFILT_READ) - { - if (flags & Acceptable) - { + if (event.filter == EVFILT_READ) { + if (flags & Acceptable) { m_callback.onSocketAcceptable(socket); } - if (flags & Readable) - { + if (flags & Readable) { m_callback.onSocketReadable(socket); } continue; } - if (event.filter == EVFILT_WRITE) - { - if (flags & Writable) - { + if (event.filter == EVFILT_WRITE) { + if (flags & Writable) { m_callback.onSocketWritable(socket); } continue; } - if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) - { + if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) { LOG_TRACE("event.filter=%s", "EVFILT_WRITE"); m_callback.onSocketClosed(socket); it->flags = Closed; struct kevent kevt; EV_SET(&kevt, event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&kevt, event.ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) - { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } continue; From adac7cf449a4b6831a4b0444758b7828490830e2 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Thu, 30 Jul 2020 23:04:14 +0000 Subject: [PATCH 30/37] Try running formatter again, default settings --- .../ext/http/server/file_http_server.h | 85 ++- .../ext/http/server/http_server.h | 527 ++++++++++-------- .../ext/http/server/socket_tools.h | 466 +++++++++------- 3 files changed, 620 insertions(+), 458 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 2e1cfa8066..77b77b0394 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -8,17 +8,19 @@ #include "opentelemetry/ext/http/server/http_server.h" -namespace HTTP_SERVER_NS { +namespace HTTP_SERVER_NS +{ -class FileHttpServer : public HTTP_SERVER_NS::HttpServer { - protected: +class FileHttpServer : public HTTP_SERVER_NS::HttpServer +{ +protected: /** * Construct the server by initializing the endpoint for serving static files, * which show up on the web if the user is on the given host:port. Static * files can be seen relative to the folder where the executable was ran. */ - FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") - : HttpServer() { + FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() + { std::ostringstream os; os << host << ":" << port; setServerName(os.str()); @@ -31,11 +33,9 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer &server) { - server[root_endpt_] = ServeFile; - } + void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } - private: +private: /** * Return whether a file is found whose location is searched for relative to * where the executable was triggered. If the file is valid, fill result with @@ -46,16 +46,18 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @returns whether a file was found and result filled with display * information */ - bool FileGetSuccess(const std::string &filename, std::vector &result) { + bool FileGetSuccess(const std::string &filename, std::vector &result) + { #ifdef _WIN32 std::replace(filename.begin(), filename.end(), '/', '\\'); #endif std::streampos size; - std::ifstream file(filename, - std::ios::in | std::ios::binary | std::ios::ate); - if (file.is_open()) { + std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { size = file.tellg(); - if (size) { + if (size) + { result.resize(size); file.seekg(0, std::ios::beg); file.read(result.data(), size); @@ -71,11 +73,11 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * @param name of the file * @returns file extension type under HTTP protocol */ - std::string GetMimeContentType(const std::string &filename) { + std::string GetMimeContentType(const std::string &filename) + { std::string file_ext = filename.substr(filename.find_last_of(".") + 1); - auto file_type = mime_types_.find(file_ext); - return (file_type != mime_types_.end()) ? file_type->second - : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + auto file_type = mime_types_.find(file_ext); + return (file_type != mime_types_.end()) ? file_type->second : HTTP_SERVER_NS::CONTENT_TYPE_TEXT; }; /** @@ -83,14 +85,17 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * assuming index.html is the wanted file if a directory is given * @param name of the file */ - std::string GetFileName(std::string S) { - if (S.back() == '/') { + std::string GetFileName(std::string S) + { + if (S.back() == '/') + { auto temp = S.substr(0, S.size() - 1); - S = temp; + S = temp; } // If filename appears to be a directory, serve the hypothetical index.html // file there - if (S.find(".") == std::string::npos) S += "/index.html"; + if (S.find(".") == std::string::npos) + S += "/index.html"; return S; } @@ -104,41 +109,35 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer { * file data */ HTTP_SERVER_NS::HttpRequestCallback ServeFile{ - [&](HTTP_SERVER_NS::HttpRequest const &req, - HTTP_SERVER_NS::HttpResponse &resp) { + [&](HTTP_SERVER_NS::HttpRequest const &req, HTTP_SERVER_NS::HttpResponse &resp) { LOG_INFO("File: %s\n", req.uri.c_str()); - auto f = GetFileName(req.uri); + auto f = GetFileName(req.uri); auto filename = f.c_str() + 1; std::vector content; - if (FileGetSuccess(filename, content)) { - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = - GetMimeContentType(filename); - resp.body = std::string(content.data(), content.size()); - resp.code = 200; - resp.message = - HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + if (FileGetSuccess(filename, content)) + { + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = GetMimeContentType(filename); + resp.body = std::string(content.data(), content.size()); + resp.code = 200; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); return resp.code; } // Two additional 'special' return codes possible here: // 0 - proceed to next handler // -1 - immediately terminate and close connection - resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = - HTTP_SERVER_NS::CONTENT_TYPE_TEXT; - resp.code = 404; - resp.message = - HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); - resp.body = resp.message; + resp.headers[HTTP_SERVER_NS::CONTENT_TYPE] = HTTP_SERVER_NS::CONTENT_TYPE_TEXT; + resp.code = 404; + resp.message = HTTP_SERVER_NS::HttpServer::getDefaultResponseMessage(resp.code); + resp.body = resp.message; return 404; }}; // Maps file extensions to their HTTP-compatible mime file type const std::unordered_map mime_types_ = { - {"css", "text/css"}, {"png", "image/png"}, - {"js", "text/javascript"}, {"htm", "text/html"}, - {"html", "text/html"}, {"json", "application/json"}, - {"txt", "text/plain"}, {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, + {"css", "text/css"}, {"png", "image/png"}, {"js", "text/javascript"}, + {"htm", "text/html"}, {"html", "text/html"}, {"json", "application/json"}, + {"txt", "text/plain"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, }; const std::string root_endpt_ = "/"; }; diff --git a/ext/include/opentelemetry/ext/http/server/http_server.h b/ext/include/opentelemetry/ext/http/server/http_server.h index d345eb3e13..672bf95c6a 100644 --- a/ext/include/opentelemetry/ext/http/server/http_server.h +++ b/ext/include/opentelemetry/ext/http/server/http_server.h @@ -21,23 +21,25 @@ #include "socket_tools.h" #ifdef HAVE_HTTP_DEBUG -#ifdef LOG_TRACE -#undef LOG_TRACE -#define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) -#endif +# ifdef LOG_TRACE +# undef LOG_TRACE +# define LOG_TRACE(x, ...) printf(x "\n", __VA_ARGS__) +# endif #endif #ifndef HTTP_SERVER_NS -#define HTTP_SERVER_NS testing +# define HTTP_SERVER_NS testing #endif -namespace HTTP_SERVER_NS { +namespace HTTP_SERVER_NS +{ -constexpr const char *CONTENT_TYPE = "Content-Type"; +constexpr const char *CONTENT_TYPE = "Content-Type"; constexpr const char *CONTENT_TYPE_TEXT = "text/plain"; -constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; +constexpr const char *CONTENT_TYPE_BIN = "application/octet-stream"; -struct HttpRequest { +struct HttpRequest +{ std::string client; std::string method; std::string uri; @@ -46,38 +48,42 @@ struct HttpRequest { std::string content; }; -struct HttpResponse { +struct HttpResponse +{ int code; std::string message; std::map headers; std::string body; }; -using CallbackFunction = - std::function; +using CallbackFunction = std::function; -class HttpRequestCallback { - protected: +class HttpRequestCallback +{ +protected: CallbackFunction callback = nullptr; - public: +public: HttpRequestCallback(){}; - HttpRequestCallback &operator=(HttpRequestCallback other) { + HttpRequestCallback &operator=(HttpRequestCallback other) + { callback = other.callback; return *this; }; HttpRequestCallback(CallbackFunction func) : callback(func){}; - HttpRequestCallback &operator=(CallbackFunction func) { + HttpRequestCallback &operator=(CallbackFunction func) + { callback = func; return (*this); } - virtual int onHttpRequest(HttpRequest const &request, - HttpResponse &response) { - if (callback != nullptr) { + virtual int onHttpRequest(HttpRequest const &request, HttpResponse &response) + { + if (callback != nullptr) + { return callback(request, response); } return 0; @@ -91,13 +97,16 @@ class HttpRequestCallback { // Out of scope: // - Performance // - Full support of RFC 7230-7237 -class HttpServer : private SocketTools::Reactor::SocketCallback { - protected: - struct Connection { +class HttpServer : private SocketTools::Reactor::SocketCallback +{ +protected: + struct Connection + { SocketTools::Socket socket; std::string receiveBuffer; std::string sendBuffer; - enum { + enum + { Idle, ReceivingHeaders, Sending100Continue, @@ -118,32 +127,36 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { SocketTools::Reactor m_reactor; std::list m_listeningSockets; - class HttpRequestHandler - : public std::pair { - public: - HttpRequestHandler(std::string key, HttpRequestCallback *value) { - first = key; + class HttpRequestHandler : public std::pair + { + public: + HttpRequestHandler(std::string key, HttpRequestCallback *value) + { + first = key; second = value; }; - HttpRequestHandler() : std::pair() { - first = ""; + HttpRequestHandler() : std::pair() + { + first = ""; second = nullptr; }; - HttpRequestHandler &operator=( - std::pair other) { - first = other.first; + HttpRequestHandler &operator=(std::pair other) + { + first = other.first; second = other.second; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback &cb) { + HttpRequestHandler &operator=(HttpRequestCallback &cb) + { second = &cb; return (*this); }; - HttpRequestHandler &operator=(HttpRequestCallback *cb) { + HttpRequestHandler &operator=(HttpRequestCallback *cb) + { second = cb; return (*this); }; @@ -154,7 +167,7 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { std::map m_connections; size_t m_maxRequestHeadersSize, m_maxRequestContentSize; - public: +public: void setKeepalive(bool keepAlive) { allowKeepalive = keepAlive; } HttpServer() @@ -164,28 +177,32 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { m_maxRequestHeadersSize(8192), m_maxRequestContentSize(2 * 1024 * 1024){}; - HttpServer(std::string serverHost, int port = 30000) : HttpServer() { + HttpServer(std::string serverHost, int port = 30000) : HttpServer() + { std::ostringstream os; os << serverHost << ":" << port; setServerName(os.str()); addListeningPort(port); }; - ~HttpServer() { - for (auto &sock : m_listeningSockets) { + ~HttpServer() + { + for (auto &sock : m_listeningSockets) + { sock.close(); } } - void setRequestLimits(size_t maxRequestHeadersSize, - size_t maxRequestContentSize) { + void setRequestLimits(size_t maxRequestHeadersSize, size_t maxRequestContentSize) + { m_maxRequestHeadersSize = maxRequestHeadersSize; m_maxRequestContentSize = maxRequestContentSize; } void setServerName(std::string const &name) { m_serverHost = name; } - int addListeningPort(int port) { + int addListeningPort(int port) + { SocketTools::Socket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); socket.setNonBlocking(); socket.setReuseAddr(); @@ -202,23 +219,24 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { return addr.port(); } - HttpRequestHandler &addHandler(const std::string &root, - HttpRequestCallback &handler) { + HttpRequestHandler &addHandler(const std::string &root, HttpRequestCallback &handler) + { // No thread-safety here! m_handlers.push_back({root, &handler}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpRequestHandler &operator[](const std::string &root) { + HttpRequestHandler &operator[](const std::string &root) + { // No thread-safety here! m_handlers.push_back({root, nullptr}); LOG_INFO("HttpServer: Added handler for %s", root.c_str()); return m_handlers.back(); } - HttpServer &operator+=( - std::pair other) { + HttpServer &operator+=(std::pair other) + { LOG_INFO("HttpServer: Added handler for %s", other.first.c_str()); m_handlers.push_back(HttpRequestHandler(other.first, &other.second)); return (*this); @@ -228,44 +246,47 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { void stop() { m_reactor.stop(); } - protected: - virtual void onSocketAcceptable(SocketTools::Socket socket) override { +protected: + virtual void onSocketAcceptable(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: accepting socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) != m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) != + m_listeningSockets.end()); SocketTools::Socket csocket; SocketTools::SocketAddr caddr; - if (socket.accept(csocket, caddr)) { + if (socket.accept(csocket, caddr)) + { csocket.setNonBlocking(); - Connection &conn = m_connections[csocket]; - conn.socket = csocket; - conn.state = Connection::Idle; + Connection &conn = m_connections[csocket]; + conn.socket = csocket; + conn.state = Connection::Idle; conn.request.client = caddr.toString(); - m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | - SocketTools::Reactor::Closed); + m_reactor.addSocket(csocket, SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); LOG_TRACE("HttpServer: [%s] accepted", conn.request.client.c_str()); } } - virtual void onSocketReadable(SocketTools::Socket socket) override { + virtual void onSocketReadable(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: reading socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) == m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) { + if (connIt == m_connections.end()) + { return; } Connection &conn = connIt->second; char buffer[2048] = {0}; - int received = socket.recv(buffer, sizeof(buffer)); - LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), - received); - if (received <= 0) { + int received = socket.recv(buffer, sizeof(buffer)); + LOG_TRACE("HttpServer: [%s] received %d", conn.request.client.c_str(), received); + if (received <= 0) + { handleConnectionClosed(conn); return; } @@ -274,32 +295,37 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { handleConnection(conn); } - virtual void onSocketWritable(SocketTools::Socket socket) override { + virtual void onSocketWritable(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: writing socket fd=0x%llx", socket.m_sock); // No thread-safety here! - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) == m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); // No thread-safety here! auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) { + if (connIt == m_connections.end()) + { return; } Connection &conn = connIt->second; - if (!sendMore(conn)) { + if (!sendMore(conn)) + { handleConnection(conn); } } - virtual void onSocketClosed(SocketTools::Socket socket) override { + virtual void onSocketClosed(SocketTools::Socket socket) override + { LOG_TRACE("HttpServer: closing socket fd=0x%llx", socket.m_sock); - assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), - socket) == m_listeningSockets.end()); + assert(std::find(m_listeningSockets.begin(), m_listeningSockets.end(), socket) == + m_listeningSockets.end()); auto connIt = m_connections.find(socket); - if (connIt == m_connections.end()) { + if (connIt == m_connections.end()) + { return; } Connection &conn = connIt->second; @@ -307,35 +333,38 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { handleConnectionClosed(conn); } - bool sendMore(Connection &conn) { - if (conn.sendBuffer.empty()) { + bool sendMore(Connection &conn) + { + if (conn.sendBuffer.empty()) + { return false; } - int sent = conn.socket.send(conn.sendBuffer.data(), - static_cast(conn.sendBuffer.size())); + int sent = conn.socket.send(conn.sendBuffer.data(), static_cast(conn.sendBuffer.size())); LOG_TRACE("HttpServer: [%s] sent %d", conn.request.client.c_str(), sent); - if (sent < 0 && - conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) { + if (sent < 0 && conn.socket.error() != SocketTools::Socket::ErrorWouldBlock) + { return true; } conn.sendBuffer.erase(0, sent); - if (!conn.sendBuffer.empty()) { - m_reactor.addSocket(conn.socket, SocketTools::Reactor::Writable | - SocketTools::Reactor::Closed); + if (!conn.sendBuffer.empty()) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Writable | SocketTools::Reactor::Closed); return true; } return false; } - protected: - void handleConnectionClosed(Connection &conn) { +protected: + void handleConnectionClosed(Connection &conn) + { LOG_TRACE("HttpServer: [%s] closed", conn.request.client.c_str()); - if (conn.state != Connection::Idle && conn.state != Connection::Closing) { - LOG_WARN("HttpServer: [%s] connection closed unexpectedly", - conn.request.client.c_str()); + if (conn.state != Connection::Idle && conn.state != Connection::Closing) + { + LOG_WARN("HttpServer: [%s] connection closed unexpectedly", conn.request.client.c_str()); } m_reactor.removeSocket(conn.socket); auto connIt = m_connections.find(conn.socket); @@ -343,43 +372,47 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { m_connections.erase(connIt); } - void handleConnection(Connection &conn) { - for (;;) { - if (conn.state == Connection::Idle) { + void handleConnection(Connection &conn) + { + for (;;) + { + if (conn.state == Connection::Idle) + { conn.response.code = 0; - conn.state = Connection::ReceivingHeaders; - LOG_TRACE("HttpServer: [%s] receiving headers", - conn.request.client.c_str()); + conn.state = Connection::ReceivingHeaders; + LOG_TRACE("HttpServer: [%s] receiving headers", conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingHeaders) { + if (conn.state == Connection::ReceivingHeaders) + { bool lfOnly = false; - size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); - if (ofs == std::string::npos) { + size_t ofs = conn.receiveBuffer.find("\r\n\r\n"); + if (ofs == std::string::npos) + { lfOnly = true; - ofs = conn.receiveBuffer.find("\n\n"); + ofs = conn.receiveBuffer.find("\n\n"); } - size_t headersLen = - (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); - if (headersLen > m_maxRequestHeadersSize) { - LOG_WARN("HttpServer: [%s] headers too long - %u", - conn.request.client.c_str(), + size_t headersLen = (ofs != std::string::npos) ? ofs : conn.receiveBuffer.length(); + if (headersLen > m_maxRequestHeadersSize) + { + LOG_WARN("HttpServer: [%s] headers too long - %u", conn.request.client.c_str(), static_cast(headersLen)); conn.response.code = 431; // Request Header Fields Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } - if (ofs == std::string::npos) { + if (ofs == std::string::npos) + { return; } - if (!parseHeaders(conn)) { - LOG_WARN("HttpServer: [%s] invalid headers", - conn.request.client.c_str()); + if (!parseHeaders(conn)) + { + LOG_WARN("HttpServer: [%s] invalid headers", conn.request.client.c_str()); conn.response.code = 400; // Bad Request - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } LOG_INFO("HttpServer: [%s] %s %s %s", conn.request.client.c_str(), @@ -387,128 +420,146 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { conn.request.protocol.c_str()); conn.receiveBuffer.erase(0, ofs + (lfOnly ? 2 : 4)); - conn.keepalive = (conn.request.protocol == "HTTP/1.1"); + conn.keepalive = (conn.request.protocol == "HTTP/1.1"); auto const connection = conn.request.headers.find("Connection"); - if (connection != conn.request.headers.end()) { - if (equalsLowercased(connection->second, "keep-alive")) { + if (connection != conn.request.headers.end()) + { + if (equalsLowercased(connection->second, "keep-alive")) + { conn.keepalive = true; - } else if (equalsLowercased(connection->second, "close")) { + } + else if (equalsLowercased(connection->second, "close")) + { conn.keepalive = false; } } auto const contentLength = conn.request.headers.find("Content-Length"); - if (contentLength != conn.request.headers.end()) { + if (contentLength != conn.request.headers.end()) + { conn.contentLength = atoi(contentLength->second.c_str()); - } else { + } + else + { conn.contentLength = 0; } - if (conn.contentLength > m_maxRequestContentSize) { - LOG_WARN("HttpServer: [%s] content too long - %u", - conn.request.client.c_str(), + if (conn.contentLength > m_maxRequestContentSize) + { + LOG_WARN("HttpServer: [%s] content too long - %u", conn.request.client.c_str(), static_cast(conn.contentLength)); conn.response.code = 413; // Payload Too Large - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } auto const expect = conn.request.headers.find("Expect"); - if (expect != conn.request.headers.end() && - conn.request.protocol == "HTTP/1.1") { - if (!equalsLowercased(expect->second, "100-continue")) { - LOG_WARN("HttpServer: [%s] unknown expectation - %s", - conn.request.client.c_str(), expect->second.c_str()); + if (expect != conn.request.headers.end() && conn.request.protocol == "HTTP/1.1") + { + if (!equalsLowercased(expect->second, "100-continue")) + { + LOG_WARN("HttpServer: [%s] unknown expectation - %s", conn.request.client.c_str(), + expect->second.c_str()); conn.response.code = 417; // Expectation Failed - conn.keepalive = false; - conn.state = Connection::Processing; + conn.keepalive = false; + conn.state = Connection::Processing; continue; } conn.sendBuffer = "HTTP/1.1 100 Continue\r\n\r\n"; - conn.state = Connection::Sending100Continue; - LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", - conn.request.client.c_str()); + conn.state = Connection::Sending100Continue; + LOG_TRACE("HttpServer: [%s] sending \"100 Continue\"", conn.request.client.c_str()); continue; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", - conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); } - if (conn.state == Connection::Sending100Continue) { - if (sendMore(conn)) { + if (conn.state == Connection::Sending100Continue) + { + if (sendMore(conn)) + { return; } conn.state = Connection::ReceivingBody; - LOG_TRACE("HttpServer: [%s] receiving body", - conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] receiving body", conn.request.client.c_str()); } - if (conn.state == Connection::ReceivingBody) { - if (conn.receiveBuffer.length() < conn.contentLength) { + if (conn.state == Connection::ReceivingBody) + { + if (conn.receiveBuffer.length() < conn.contentLength) + { return; } - if (conn.receiveBuffer.length() == conn.contentLength) { + if (conn.receiveBuffer.length() == conn.contentLength) + { conn.request.content = std::move(conn.receiveBuffer); conn.receiveBuffer.clear(); - } else { - conn.request.content.assign(conn.receiveBuffer, 0, - conn.contentLength); + } + else + { + conn.request.content.assign(conn.receiveBuffer, 0, conn.contentLength); conn.receiveBuffer.erase(0, conn.contentLength); } conn.state = Connection::Processing; - LOG_TRACE("HttpServer: [%s] processing request", - conn.request.client.c_str()); + LOG_TRACE("HttpServer: [%s] processing request", conn.request.client.c_str()); } - if (conn.state == Connection::Processing) { + if (conn.state == Connection::Processing) + { processRequest(conn); std::ostringstream os; - os << conn.request.protocol << ' ' << conn.response.code << ' ' - << conn.response.message << "\r\n"; - for (auto const &header : conn.response.headers) { + os << conn.request.protocol << ' ' << conn.response.code << ' ' << conn.response.message + << "\r\n"; + for (auto const &header : conn.response.headers) + { os << header.first << ": " << header.second << "\r\n"; } os << "\r\n"; conn.sendBuffer = os.str(); - conn.state = Connection::SendingHeaders; - LOG_TRACE("HttpServer: [%s] sending headers", - conn.request.client.c_str()); + conn.state = Connection::SendingHeaders; + LOG_TRACE("HttpServer: [%s] sending headers", conn.request.client.c_str()); } - if (conn.state == Connection::SendingHeaders) { - if (sendMore(conn)) { + if (conn.state == Connection::SendingHeaders) + { + if (sendMore(conn)) + { return; } conn.sendBuffer = std::move(conn.response.body); - conn.state = Connection::SendingBody; + conn.state = Connection::SendingBody; LOG_TRACE("HttpServer: [%s] sending body", conn.request.client.c_str()); } - if (conn.state == Connection::SendingBody) { - if (sendMore(conn)) { + if (conn.state == Connection::SendingBody) + { + if (sendMore(conn)) + { return; } conn.keepalive &= allowKeepalive; - if (conn.keepalive) { - m_reactor.addSocket(conn.socket, SocketTools::Reactor::Readable | - SocketTools::Reactor::Closed); + if (conn.keepalive) + { + m_reactor.addSocket(conn.socket, + SocketTools::Reactor::Readable | SocketTools::Reactor::Closed); conn.state = Connection::Idle; - LOG_TRACE("HttpServer: [%s] idle (keep-alive)", - conn.request.client.c_str()); - if (conn.receiveBuffer.empty()) { + LOG_TRACE("HttpServer: [%s] idle (keep-alive)", conn.request.client.c_str()); + if (conn.receiveBuffer.empty()) + { return; } - } else { + } + else + { conn.socket.shutdown(SocketTools::Socket::ShutdownSend); m_reactor.addSocket(conn.socket, SocketTools::Reactor::Closed); conn.state = Connection::Closing; @@ -516,94 +567,114 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { } } - if (conn.state == Connection::Closing) { + if (conn.state == Connection::Closing) + { return; } } } - bool parseHeaders(Connection &conn) { + bool parseHeaders(Connection &conn) + { // Method char const *begin = conn.receiveBuffer.c_str(); - char const *ptr = begin; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + char const *ptr = begin; + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != ' ') { + if (*ptr != ' ') + { return false; } conn.request.method.assign(begin, ptr); - while (*ptr == ' ') { + while (*ptr == ' ') + { ptr++; } // URI begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != ' ') { + if (*ptr != ' ') + { return false; } conn.request.uri.assign(begin, ptr); - while (*ptr == ' ') { + while (*ptr == ' ') + { ptr++; } // Protocol begin = ptr; - while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { + while (*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != '\r' && *ptr != '\n') { + if (*ptr != '\r' && *ptr != '\n') + { return false; } conn.request.protocol.assign(begin, ptr); - if (*ptr == '\r') { + if (*ptr == '\r') + { ptr++; } - if (*ptr != '\n') { + if (*ptr != '\n') + { return false; } ptr++; // Headers conn.request.headers.clear(); - while (*ptr != '\r' && *ptr != '\n') { + while (*ptr != '\r' && *ptr != '\n') + { // Name begin = ptr; - while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && - *ptr != '\n') { + while (*ptr && *ptr != ':' && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') + { ptr++; } - if (*ptr != ':') { + if (*ptr != ':') + { return false; } std::string name = normalizeHeaderName(begin, ptr); ptr++; - while (*ptr == ' ') { + while (*ptr == ' ') + { ptr++; } // Value begin = ptr; - while (*ptr && *ptr != '\r' && *ptr != '\n') { + while (*ptr && *ptr != '\r' && *ptr != '\n') + { ptr++; } conn.request.headers[name] = std::string(begin, ptr); - if (*ptr == '\r') { + if (*ptr == '\r') + { ptr++; } - if (*ptr != '\n') { + if (*ptr != '\n') + { return false; } ptr++; } - if (*ptr == '\r') { + if (*ptr == '\r') + { ptr++; } - if (*ptr != '\n') { + if (*ptr != '\n') + { return false; } ptr++; @@ -611,75 +682,87 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { return true; } - static bool equalsLowercased(std::string const &str, char const *mask) { + static bool equalsLowercased(std::string const &str, char const *mask) + { char const *ptr = str.c_str(); - while (*ptr && *mask && ::tolower(*ptr) == *mask) { + while (*ptr && *mask && ::tolower(*ptr) == *mask) + { ptr++; mask++; } return !*ptr && !*mask; } - static std::string normalizeHeaderName(char const *begin, char const *end) { + static std::string normalizeHeaderName(char const *begin, char const *end) + { std::string result(begin, end); bool first = true; - for (char &ch : result) { - if (first) { - ch = static_cast(::toupper(ch)); + for (char &ch : result) + { + if (first) + { + ch = static_cast(::toupper(ch)); first = false; - } else if (ch == '-') { + } + else if (ch == '-') + { first = true; - } else { + } + else + { ch = static_cast(::tolower(ch)); } } return result; } - void processRequest(Connection &conn) { + void processRequest(Connection &conn) + { conn.response.message.clear(); conn.response.headers.clear(); conn.response.body.clear(); - if (conn.response.code == 0) { + if (conn.response.code == 0) + { conn.response.code = 404; // Not Found - for (auto &handler : m_handlers) { + for (auto &handler : m_handlers) + { if (conn.request.uri.length() >= handler.first.length() && - strncmp(conn.request.uri.c_str(), handler.first.c_str(), - handler.first.length()) == 0) { - LOG_TRACE("HttpServer: [%s] using handler for %s", - conn.request.client.c_str(), handler.first.c_str()); + strncmp(conn.request.uri.c_str(), handler.first.c_str(), handler.first.length()) == 0) + { + LOG_TRACE("HttpServer: [%s] using handler for %s", conn.request.client.c_str(), + handler.first.c_str()); // auto callback = handler.second; // Bazel gets mad at this unused // var, uncomment when using - int result = - handler.second->onHttpRequest(conn.request, conn.response); - if (result != 0) { + int result = handler.second->onHttpRequest(conn.request, conn.response); + if (result != 0) + { conn.response.code = result; break; } } } - if (conn.response.code == -1) { - LOG_TRACE("HttpServer: [%s] closing by request", - conn.request.client.c_str()); + if (conn.response.code == -1) + { + LOG_TRACE("HttpServer: [%s] closing by request", conn.request.client.c_str()); handleConnectionClosed(conn); } } - if (conn.response.message.empty()) { + if (conn.response.message.empty()) + { conn.response.message = getDefaultResponseMessage(conn.response.code); } - conn.response.headers["Host"] = m_serverHost; - conn.response.headers["Connection"] = - (conn.keepalive ? "keep-alive" : "close"); - conn.response.headers["Date"] = formatTimestamp(time(nullptr)); - conn.response.headers["Content-Length"] = - std::to_string(conn.response.body.size()); + conn.response.headers["Host"] = m_serverHost; + conn.response.headers["Connection"] = (conn.keepalive ? "keep-alive" : "close"); + conn.response.headers["Date"] = formatTimestamp(time(nullptr)); + conn.response.headers["Content-Length"] = std::to_string(conn.response.body.size()); } - static std::string formatTimestamp(time_t time) { + static std::string formatTimestamp(time_t time) + { tm tm; #ifdef _WIN32 gmtime_s(&tm, &time); @@ -691,9 +774,11 @@ class HttpServer : private SocketTools::Reactor::SocketCallback { return buf; } - public: - static char const *getDefaultResponseMessage(int code) { - switch (code) { +public: + static char const *getDefaultResponseMessage(int code) + { + switch (code) + { // *INDENT-OFF* case 100: return "Continue"; diff --git a/ext/include/opentelemetry/ext/http/server/socket_tools.h b/ext/include/opentelemetry/ext/http/server/socket_tools.h index 0d9c8667ab..5c135b7a2a 100644 --- a/ext/include/opentelemetry/ext/http/server/socket_tools.h +++ b/ext/include/opentelemetry/ext/http/server/socket_tools.h @@ -28,70 +28,72 @@ //# include -#include +# include // TODO: consider NOMINMAX -#undef min -#undef max -#pragma comment(lib, "ws2_32.lib") +# undef min +# undef max +# pragma comment(lib, "ws2_32.lib") #else -#include +# include -#ifdef __linux__ -#include -#endif +# ifdef __linux__ +# include +# endif -#if __APPLE__ -#include "TargetConditionals.h" +# if __APPLE__ +# include "TargetConditionals.h" // Use kqueue on mac -#include -#include -#include -#endif +# include +# include +# include +# endif // Common POSIX headers for Linux and Mac OS X -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include #endif #ifndef _Out_cap_ -#define _Out_cap_(size) +# define _Out_cap_(size) #endif #if defined(HAVE_CONSOLE_LOG) && !defined(LOG_DEBUG) // Log to console if there's no standard log facility defined -#include -#ifndef LOG_DEBUG -#define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) -#endif +# include +# ifndef LOG_DEBUG +# define LOG_DEBUG(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_TRACE(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_INFO(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_WARN(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_ERROR(fmt_, ...) printf(" " fmt_ "\n", ##__VA_ARGS__) +# endif #endif #ifndef LOG_DEBUG // Don't log anything if there's no standard log facility defined -#define LOG_DEBUG(fmt_, ...) -#define LOG_TRACE(fmt_, ...) -#define LOG_INFO(fmt_, ...) -#define LOG_WARN(fmt_, ...) -#define LOG_ERROR(fmt_, ...) +# define LOG_DEBUG(fmt_, ...) +# define LOG_TRACE(fmt_, ...) +# define LOG_INFO(fmt_, ...) +# define LOG_WARN(fmt_, ...) +# define LOG_ERROR(fmt_, ...) #endif -namespace common { +namespace common +{ /// /// A simple thread, derived class overloads onThread() method. /// -struct Thread { +struct Thread +{ std::thread m_thread; volatile bool m_terminate{false}; @@ -105,17 +107,20 @@ struct Thread { /// /// Start Thread /// - void startThread() { + void startThread() + { m_terminate = false; - m_thread = std::thread([&]() { this->onThread(); }); + m_thread = std::thread([&]() { this->onThread(); }); } /// /// Join Thread /// - void joinThread() { + void joinThread() + { m_terminate = true; - if (m_thread.joinable()) { + if (m_thread.joinable()) + { m_thread.join(); } } @@ -139,13 +144,16 @@ struct Thread { }; }; // namespace common -namespace SocketTools { +namespace SocketTools +{ #ifdef _WIN32 // WinSocks need extra (de)initialization, solved by a global object here, // whose constructor/destructor will be called before and after main(). -struct WsaInitializer { - WsaInitializer() { +struct WsaInitializer +{ + WsaInitializer() + { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); } @@ -160,7 +168,8 @@ static WsaInitializer g_wsaInitializer; /// /// Encapsulation of sockaddr(_in) /// -struct SocketAddr { +struct SocketAddr +{ static u_long const Loopback = 0x7F000001; sockaddr m_data; @@ -171,33 +180,39 @@ struct SocketAddr { /// SocketAddr SocketAddr() { memset(&m_data, 0, sizeof(m_data)); } - SocketAddr(u_long addr, int port) { - sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - inet4.sin_port = htons(static_cast(port)); + SocketAddr(u_long addr, int port) + { + sockaddr_in &inet4 = reinterpret_cast(m_data); + inet4.sin_family = AF_INET; + inet4.sin_port = htons(static_cast(port)); inet4.sin_addr.s_addr = htonl(addr); } - SocketAddr(char const *addr) { + SocketAddr(char const *addr) + { #ifdef _WIN32 INT addrlen = sizeof(m_data); WCHAR buf[200]; - for (int i = 0; i < sizeof(buf) && addr[i]; i++) { + for (int i = 0; i < sizeof(buf) && addr[i]; i++) + { buf[i] = addr[i]; } buf[199] = L'\0'; ::WSAStringToAddressW(buf, AF_INET, nullptr, &m_data, &addrlen); #else sockaddr_in &inet4 = reinterpret_cast(m_data); - inet4.sin_family = AF_INET; - char const *colon = strchr(addr, ':'); - if (colon) { + inet4.sin_family = AF_INET; + char const *colon = strchr(addr, ':'); + if (colon) + { inet4.sin_port = htons(atoi(colon + 1)); char buf[16]; memcpy(buf, addr, std::min(15, colon - addr)); buf[15] = '\0'; ::inet_pton(AF_INET, buf, &inet4.sin_addr); - } else { + } + else + { inet4.sin_port = 0; ::inet_pton(AF_INET, addr, &inet4.sin_addr); } @@ -212,11 +227,12 @@ struct SocketAddr { operator const sockaddr *() const { return &m_data; } - int port() const { - switch (m_data.sa_family) { + int port() const + { + switch (m_data.sa_family) + { case AF_INET: { - sockaddr_in const &inet4 = - reinterpret_cast(m_data); + sockaddr_in const &inet4 = reinterpret_cast(m_data); return ntohs(inet4.sin_port); } @@ -225,16 +241,17 @@ struct SocketAddr { } } - std::string toString() const { + std::string toString() const + { std::ostringstream os; - switch (m_data.sa_family) { + switch (m_data.sa_family) + { case AF_INET: { - sockaddr_in const &inet4 = - reinterpret_cast(m_data); - u_long addr = ntohl(inet4.sin_addr.s_addr); - os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' - << ((addr >> 8) & 255) << '.' << (addr & 255); + sockaddr_in const &inet4 = reinterpret_cast(m_data); + u_long addr = ntohl(inet4.sin_addr.s_addr); + os << (addr >> 24) << '.' << ((addr >> 16) & 255) << '.' << ((addr >> 8) & 255) << '.' + << (addr & 255); os << ':' << ntohs(inet4.sin_port); break; } @@ -249,7 +266,8 @@ struct SocketAddr { /// /// Encapsulation of a socket (non-exclusive ownership) /// -struct Socket { +struct Socket +{ #ifdef _WIN32 typedef SOCKET Type; static Type const Invalid = INVALID_SOCKET; @@ -268,19 +286,16 @@ struct Socket { operator Socket::Type() const { return m_sock; } - bool operator==(Socket const &other) const { - return (m_sock == other.m_sock); - } + bool operator==(Socket const &other) const { return (m_sock == other.m_sock); } - bool operator!=(Socket const &other) const { - return (m_sock != other.m_sock); - } + bool operator!=(Socket const &other) const { return (m_sock != other.m_sock); } bool operator<(Socket const &other) const { return (m_sock < other.m_sock); } bool invalid() const { return (m_sock == Invalid); } - void setNonBlocking() { + void setNonBlocking() + { assert(m_sock != Invalid); #ifdef _WIN32 u_long value = 1; @@ -291,34 +306,38 @@ struct Socket { #endif } - bool setReuseAddr() { + bool setReuseAddr() + { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&value), sizeof(value)) == 0); + return (::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&value), + sizeof(value)) == 0); } - bool setNoDelay() { + bool setNoDelay() + { assert(m_sock != Invalid); #ifdef _WIN32 BOOL value = TRUE; #else int value = 1; #endif - return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&value), sizeof(value)) == 0); + return (::setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&value), + sizeof(value)) == 0); } - bool connect(SocketAddr const &addr) { + bool connect(SocketAddr const &addr) + { assert(m_sock != Invalid); return (::connect(m_sock, addr, sizeof(addr)) == 0); } - void close() { + void close() + { assert(m_sock != Invalid); #ifdef _WIN32 ::closesocket(m_sock); @@ -328,25 +347,27 @@ struct Socket { m_sock = Invalid; } - int recv(_Out_cap_(size) void *buffer, unsigned size) { + int recv(_Out_cap_(size) void *buffer, unsigned size) + { assert(m_sock != Invalid); int flags = 0; - return static_cast( - ::recv(m_sock, reinterpret_cast(buffer), size, flags)); + return static_cast(::recv(m_sock, reinterpret_cast(buffer), size, flags)); } - int send(void const *buffer, unsigned size) { + int send(void const *buffer, unsigned size) + { assert(m_sock != Invalid); - return static_cast( - ::send(m_sock, reinterpret_cast(buffer), size, 0)); + return static_cast(::send(m_sock, reinterpret_cast(buffer), size, 0)); } - bool bind(SocketAddr const &addr) { + bool bind(SocketAddr const &addr) + { assert(m_sock != Invalid); return (::bind(m_sock, addr, sizeof(addr)) == 0); } - bool getsockname(SocketAddr &addr) const { + bool getsockname(SocketAddr &addr) const + { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(addr); @@ -356,12 +377,14 @@ struct Socket { return (::getsockname(m_sock, addr, &addrlen) == 0); } - bool listen(int backlog) { + bool listen(int backlog) + { assert(m_sock != Invalid); return (::listen(m_sock, backlog) == 0); } - bool accept(Socket &csock, SocketAddr &caddr) { + bool accept(Socket &csock, SocketAddr &caddr) + { assert(m_sock != Invalid); #ifdef _WIN32 int addrlen = sizeof(caddr); @@ -372,12 +395,14 @@ struct Socket { return !csock.invalid(); } - bool shutdown(int how) { + bool shutdown(int how) + { assert(m_sock != Invalid); return (::shutdown(m_sock, how) == 0); } - int error() const { + int error() const + { #ifdef _WIN32 return ::WSAGetLastError(); #else @@ -385,7 +410,8 @@ struct Socket { #endif } - enum { + enum + { #ifdef _WIN32 ErrorWouldBlock = WSAEWOULDBLOCK #else @@ -393,15 +419,16 @@ struct Socket { #endif }; - enum { + enum + { #ifdef _WIN32 ShutdownReceive = SD_RECEIVE, - ShutdownSend = SD_SEND, - ShutdownBoth = SD_BOTH + ShutdownSend = SD_SEND, + ShutdownBoth = SD_BOTH #else ShutdownReceive = SHUT_RD, - ShutdownSend = SHUT_WR, - ShutdownBoth = SHUT_RDWR + ShutdownSend = SHUT_WR, + ShutdownBoth = SHUT_RDWR #endif }; }; @@ -409,7 +436,8 @@ struct Socket { /// /// Socket Data /// -struct SocketData { +struct SocketData +{ Socket socket; int flags; @@ -421,22 +449,30 @@ struct SocketData { /// /// Socket Reactor /// -struct Reactor : protected common::Thread { +struct Reactor : protected common::Thread +{ /// /// Socket State callback /// - class SocketCallback { - public: - virtual void onSocketReadable(Socket sock) = 0; - virtual void onSocketWritable(Socket sock) = 0; + class SocketCallback + { + public: + virtual void onSocketReadable(Socket sock) = 0; + virtual void onSocketWritable(Socket sock) = 0; virtual void onSocketAcceptable(Socket sock) = 0; - virtual void onSocketClosed(Socket sock) = 0; + virtual void onSocketClosed(Socket sock) = 0; }; /// /// Socket State /// - enum State { Readable = 1, Writable = 2, Acceptable = 4, Closed = 8 }; + enum State + { + Readable = 1, + Writable = 2, + Acceptable = 4, + Closed = 8 + }; SocketCallback &m_callback; @@ -454,19 +490,20 @@ struct Reactor : protected common::Thread { #ifdef TARGET_OS_MAC /* use kqueue on Mac */ -#define KQUEUE_SIZE 32 +# define KQUEUE_SIZE 32 int kq{0}; struct kevent m_events[KQUEUE_SIZE]; #endif - public: - Reactor(SocketCallback &callback) : m_callback(callback) { +public: + Reactor(SocketCallback &callback) : m_callback(callback) + { #ifdef __linux__ -#ifdef ANDROID +# ifdef ANDROID m_epollFd = ::epoll_create(0); -#else +# else m_epollFd = ::epoll_create1(0); -#endif +# endif #endif #ifdef TARGET_OS_MAC @@ -475,7 +512,8 @@ struct Reactor : protected common::Thread { #endif } - ~Reactor() { + ~Reactor() + { #ifdef __linux__ ::close(m_epollFd); #endif @@ -489,21 +527,25 @@ struct Reactor : protected common::Thread { /// /// /// - void addSocket(const Socket &socket, int flags) { - if (flags == 0) { + void addSocket(const Socket &socket, int flags) + { + if (flags == 0) + { removeSocket(socket); - } else { + } + else + { auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it == m_sockets.end()) { - LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", - static_cast(socket), flags); + if (it == m_sockets.end()) + { + LOG_TRACE("Reactor: Adding socket 0x%x with flags 0x%x", static_cast(socket), flags); #ifdef _WIN32 m_events.push_back(::WSACreateEvent()); #endif #ifdef __linux__ epoll_event event = {}; - event.data.fd = socket; - event.events = 0; + event.data.fd = socket; + event.events = 0; ::epoll_ctl(m_epollFd, EPOLL_CTL_ADD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -517,27 +559,33 @@ struct Reactor : protected common::Thread { #endif m_sockets.push_back(SocketData()); m_sockets.back().socket = socket; - m_sockets.back().flags = 0; - it = m_sockets.end() - 1; - } else { - LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", - static_cast(socket), flags); + m_sockets.back().flags = 0; + it = m_sockets.end() - 1; + } + else + { + LOG_TRACE("Reactor: Updating socket 0x%x with flags 0x%x", static_cast(socket), flags); } - if (it->flags != flags) { + if (it->flags != flags) + { it->flags = flags; #ifdef _WIN32 long lNetworkEvents = 0; - if (it->flags & Readable) { + if (it->flags & Readable) + { lNetworkEvents |= FD_READ; } - if (it->flags & Writable) { + if (it->flags & Writable) + { lNetworkEvents |= FD_WRITE; } - if (it->flags & Acceptable) { + if (it->flags & Acceptable) + { lNetworkEvents |= FD_ACCEPT; } - if (it->flags & Closed) { + if (it->flags & Closed) + { lNetworkEvents |= FD_CLOSE; } auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); @@ -545,19 +593,22 @@ struct Reactor : protected common::Thread { #endif #ifdef __linux__ int events = 0; - if (it->flags & Readable) { + if (it->flags & Readable) + { events |= EPOLLIN; } - if (it->flags & Writable) { + if (it->flags & Writable) + { events |= EPOLLOUT; } - if (it->flags & Acceptable) { + if (it->flags & Acceptable) + { events |= EPOLLIN; } // if (it->flags & Closed) - always handled (EPOLLERR | EPOLLHUP) epoll_event event = {}; - event.data.fd = socket; - event.events = events; + event.data.fd = socket; + event.events = events; ::epoll_ctl(m_epollFd, EPOLL_CTL_MOD, socket, &event); #endif #ifdef TARGET_OS_MAC @@ -571,10 +622,12 @@ struct Reactor : protected common::Thread { /// Remove Socket /// /// - void removeSocket(const Socket &socket) { + void removeSocket(const Socket &socket) + { LOG_TRACE("Reactor: Removing socket 0x%x", static_cast(socket)); auto it = std::find(m_sockets.begin(), m_sockets.end(), socket); - if (it != m_sockets.end()) { + if (it != m_sockets.end()) + { #ifdef _WIN32 auto eventIt = m_events.begin() + std::distance(m_sockets.begin(), it); ::WSAEventSelect(it->socket, *eventIt, 0); @@ -589,12 +642,14 @@ struct Reactor : protected common::Thread { bzero(&event, sizeof(event)); event.ident = socket; EV_SET(&event, socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { //// Already removed? LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } @@ -606,7 +661,8 @@ struct Reactor : protected common::Thread { /// /// Start server /// - void start() { + void start() + { LOG_INFO("Reactor: Starting..."); startThread(); } @@ -614,31 +670,36 @@ struct Reactor : protected common::Thread { /// /// Stop server /// - void stop() { + void stop() + { LOG_INFO("Reactor: Stopping..."); joinThread(); #ifdef _WIN32 - for (auto &hEvent : m_events) { + for (auto &hEvent : m_events) + { ::WSACloseEvent(hEvent); } #else /* Linux and Mac */ - for (auto &sd : m_sockets) { -#ifdef __linux__ + for (auto &sd : m_sockets) + { +# ifdef __linux__ ::epoll_ctl(m_epollFd, EPOLL_CTL_DEL, sd.socket, nullptr); -#endif -#ifdef TARGET_OS_MAC +# endif +# ifdef TARGET_OS_MAC struct kevent event; bzero(&event, sizeof(event)); event.ident = sd.socket; EV_SET(&event, sd.socket, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&event, sd.socket, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &event, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } -#endif +# endif } #endif m_sockets.clear(); @@ -647,21 +708,23 @@ struct Reactor : protected common::Thread { /// /// Thread Loop for async events processing /// - virtual void onThread() override { + virtual void onThread() override + { LOG_INFO("Reactor: Thread started"); - while (!shouldTerminate()) { + while (!shouldTerminate()) + { #ifdef _WIN32 - DWORD dwResult = - ::WSAWaitForMultipleEvents(static_cast(m_events.size()), - m_events.data(), FALSE, 500, FALSE); - if (dwResult == WSA_WAIT_TIMEOUT) { + DWORD dwResult = ::WSAWaitForMultipleEvents(static_cast(m_events.size()), + m_events.data(), FALSE, 500, FALSE); + if (dwResult == WSA_WAIT_TIMEOUT) + { continue; } assert(dwResult <= WSA_WAIT_EVENT_0 + m_events.size()); - int index = dwResult - WSA_WAIT_EVENT_0; + int index = dwResult - WSA_WAIT_EVENT_0; Socket socket = m_sockets[index].socket; - int flags = m_sockets[index].flags; + int flags = m_sockets[index].flags; WSANETWORKEVENTS ne; ::WSAEnumNetworkEvents(socket, m_events[index], &ne); @@ -670,51 +733,57 @@ struct Reactor : protected common::Thread { "(armed 0x%x)", static_cast(socket), index, ne.lNetworkEvents, flags); - if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) { + if ((flags & Readable) && (ne.lNetworkEvents & FD_READ)) + { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) { + if ((flags & Writable) && (ne.lNetworkEvents & FD_WRITE)) + { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) { + if ((flags & Acceptable) && (ne.lNetworkEvents & FD_ACCEPT)) + { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) { + if ((flags & Closed) && (ne.lNetworkEvents & FD_CLOSE)) + { m_callback.onSocketClosed(socket); } #endif #ifdef __linux__ epoll_event events[4]; - int result = ::epoll_wait(m_epollFd, events, - sizeof(events) / sizeof(events[0]), 500); - if (result == 0 || (result == -1 && errno == EINTR)) { + int result = ::epoll_wait(m_epollFd, events, sizeof(events) / sizeof(events[0]), 500); + if (result == 0 || (result == -1 && errno == EINTR)) + { continue; } - assert(result >= 1 && - static_cast(result) <= sizeof(events) / sizeof(events[0])); - for (int i = 0; i < result; i++) { - auto it = - std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); + assert(result >= 1 && static_cast(result) <= sizeof(events) / sizeof(events[0])); + for (int i = 0; i < result; i++) + { + auto it = std::find(m_sockets.begin(), m_sockets.end(), events[i].data.fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE( - "Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", - static_cast(socket), events[i].events, flags); + LOG_TRACE("Reactor: Handling socket 0x%x active flags 0x%x (armed 0x%x)", + static_cast(socket), events[i].events, flags); - if ((flags & Readable) && (events[i].events & EPOLLIN)) { + if ((flags & Readable) && (events[i].events & EPOLLIN)) + { m_callback.onSocketReadable(socket); } - if ((flags & Writable) && (events[i].events & EPOLLOUT)) { + if ((flags & Writable) && (events[i].events & EPOLLOUT)) + { m_callback.onSocketWritable(socket); } - if ((flags & Acceptable) && (events[i].events & EPOLLIN)) { + if ((flags & Acceptable) && (events[i].events & EPOLLIN)) + { m_callback.onSocketAcceptable(socket); } - if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) { + if ((flags & Closed) && (events[i].events & (EPOLLHUP | EPOLLERR))) + { m_callback.onSocketClosed(socket); } } @@ -723,49 +792,58 @@ struct Reactor : protected common::Thread { #if defined(TARGET_OS_MAC) unsigned waitms = 500; // never block for more than 500ms struct timespec timeout; - timeout.tv_sec = waitms / 1000; + timeout.tv_sec = waitms / 1000; timeout.tv_nsec = (waitms % 1000) * 1000 * 1000; int nev = kevent(kq, NULL, 0, m_events, KQUEUE_SIZE, &timeout); - for (int i = 0; i < nev; i++) { + for (int i = 0; i < nev; i++) + { struct kevent &event = m_events[i]; - int fd = (int)event.ident; - auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); + int fd = (int)event.ident; + auto it = std::find(m_sockets.begin(), m_sockets.end(), fd); assert(it != m_sockets.end()); Socket socket = it->socket; - int flags = it->flags; + int flags = it->flags; - LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", - static_cast(socket), event.flags, event.fflags); + LOG_TRACE("Handling socket 0x%x active flags 0x%x (armed 0x%x)", static_cast(socket), + event.flags, event.fflags); - if (event.filter == EVFILT_READ) { - if (flags & Acceptable) { + if (event.filter == EVFILT_READ) + { + if (flags & Acceptable) + { m_callback.onSocketAcceptable(socket); } - if (flags & Readable) { + if (flags & Readable) + { m_callback.onSocketReadable(socket); } continue; } - if (event.filter == EVFILT_WRITE) { - if (flags & Writable) { + if (event.filter == EVFILT_WRITE) + { + if (flags & Writable) + { m_callback.onSocketWritable(socket); } continue; } - if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) { + if ((event.flags & EV_EOF) || (event.flags & EV_ERROR)) + { LOG_TRACE("event.filter=%s", "EVFILT_WRITE"); m_callback.onSocketClosed(socket); it->flags = Closed; struct kevent kevt; EV_SET(&kevt, event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } EV_SET(&kevt, event.ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) { + if (-1 == kevent(kq, &kevt, 1, NULL, 0, NULL)) + { LOG_ERROR("cannot delete fd=0x%x from kqueue!", event.ident); } continue; From 700d4235b7e2fd93b3f74b040423e973c56536ab Mon Sep 17 00:00:00 2001 From: Keshav Manghat Date: Fri, 31 Jul 2020 00:52:42 +0000 Subject: [PATCH 31/37] Loop fix and example update --- examples/zpages/zpages_example.cc | 15 ++++++++------- ext/src/zpages/tracez_http_server.cc | 5 ++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/zpages/zpages_example.cc b/examples/zpages/zpages_example.cc index a141e3548f..948b063f96 100644 --- a/examples/zpages/zpages_example.cc +++ b/examples/zpages/zpages_example.cc @@ -12,7 +12,8 @@ int main(int argc, char* argv[]) { /** * The following line initializes zPages and starts a webserver at - * http://localhost:30000/tracez/ where spans that are created can be viewed. + * http://localhost:30000/tracez/ where spans that are created in the application + * can be viewed. * Note that the webserver is destroyed after the application ends execution. */ zPages(); @@ -20,22 +21,22 @@ int main(int argc, char* argv[]) { auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(""); // Create a span of each type(running, completed and error) - auto running_span = tracer->StartSpan("example span"); - tracer->StartSpan("example span")->End(); - tracer->StartSpan("example span")->SetStatus( + auto running_span = tracer->StartSpan("examplespan"); + tracer->StartSpan("examplespan")->End(); + tracer->StartSpan("examplespan")->SetStatus( opentelemetry::trace::CanonicalCode::CANCELLED, "Cancelled example"); // Change the name of the running span and end it - running_span->UpdateName("example span2"); + running_span->UpdateName("examplespan2"); running_span->End(); // Create another running span with a different name - auto running_span2 = tracer->StartSpan("example span2"); + auto running_span2 = tracer->StartSpan("examplespan2"); // Create a completed span every second till user stops the loop std::cout << "Presss CTRL+C to stop...\n"; while(true){ std::this_thread::sleep_for(seconds(1)); - tracer->StartSpan("example span")->End(); + tracer->StartSpan("examplespan")->End(); } } diff --git a/ext/src/zpages/tracez_http_server.cc b/ext/src/zpages/tracez_http_server.cc index cb3546dcf6..392a8b7370 100644 --- a/ext/src/zpages/tracez_http_server.cc +++ b/ext/src/zpages/tracez_http_server.cc @@ -1,5 +1,5 @@ #include "opentelemetry/ext/zpages/tracez_http_server.h" - +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace ext { namespace zpages { @@ -17,8 +17,7 @@ namespace zpages { const auto &complete_ok_counts = buckets.completed_span_count_per_latency_bucket; auto latency_counts = json::array(); - for (auto boundary = LatencyBoundary::k0MicroTo10Micro; - boundary != LatencyBoundary::k100SecondToMax; ++boundary) { + for (unsigned int boundary = 0; boundary < kLatencyBoundaries.size(); boundary++){ latency_counts.push_back(complete_ok_counts[boundary]); } From 4ff777c231b3f7a427d4c57fdbbe0c7bf0f3d8c5 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Fri, 31 Jul 2020 13:40:52 +0000 Subject: [PATCH 32/37] Fix wrong type inputs --- ext/include/opentelemetry/ext/http/server/file_http_server.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/include/opentelemetry/ext/http/server/file_http_server.h b/ext/include/opentelemetry/ext/http/server/file_http_server.h index 77b77b0394..0b4d3cccc9 100644 --- a/ext/include/opentelemetry/ext/http/server/file_http_server.h +++ b/ext/include/opentelemetry/ext/http/server/file_http_server.h @@ -19,7 +19,7 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * which show up on the web if the user is on the given host:port. Static * files can be seen relative to the folder where the executable was ran. */ - FileHttpServer(const std::string &host = "127.0.0.1", int port = "3333") : HttpServer() + FileHttpServer(const std::string &host = "127.0.0.1", int port = 3333) : HttpServer() { std::ostringstream os; os << host << ":" << port; @@ -33,7 +33,7 @@ class FileHttpServer : public HTTP_SERVER_NS::HttpServer * initialize their own, otherwise everything will be served like a file * @param server should be an instance of this object */ - void InitializeFileEndpoint(zPagesHttpServer &server) { server[root_endpt_] = ServeFile; } + void InitializeFileEndpoint(FileHttpServer &server) { server[root_endpt_] = ServeFile; } private: /** From 516f3d97eab4fc801056c0aac5f0890cca0e0a0d Mon Sep 17 00:00:00 2001 From: Keshav Manghat Date: Fri, 31 Jul 2020 19:01:16 +0000 Subject: [PATCH 33/37] Removed import --- ext/src/zpages/tracez_http_server.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/src/zpages/tracez_http_server.cc b/ext/src/zpages/tracez_http_server.cc index 392a8b7370..1ace4b0ed1 100644 --- a/ext/src/zpages/tracez_http_server.cc +++ b/ext/src/zpages/tracez_http_server.cc @@ -1,5 +1,5 @@ #include "opentelemetry/ext/zpages/tracez_http_server.h" -#include + OPENTELEMETRY_BEGIN_NAMESPACE namespace ext { namespace zpages { From 616289217054ea51845f2fb03e7e4990ef64fe40 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Fri, 31 Jul 2020 19:08:44 +0000 Subject: [PATCH 34/37] Turn on and render attributes correctly --- .../ext/zpages/static/tracez_script.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ext/include/opentelemetry/ext/zpages/static/tracez_script.h b/ext/include/opentelemetry/ext/zpages/static/tracez_script.h index d1e5743bd7..db456164ed 100644 --- a/ext/include/opentelemetry/ext/zpages/static/tracez_script.h +++ b/ext/include/opentelemetry/ext/zpages/static/tracez_script.h @@ -52,13 +52,13 @@ const char tracez_script[] = "window.onload = () => refreshData();" " onclick=\"overwriteDetailedTable(${i}, '${span['name']}')\"`}>${span[h][i]}`;" "" "/* Pretty print a cell with a map */" -"const getKeyValueCell = (span, i, h) => `" -" ${JSON.stringify(span[h][i], null, 2)}" +"const getKeyValueCell = (span, h) => `" +" ${JSON.stringify(span[h], null, 2)}" " `;" "" "/* Standard categories when checking span details */" "const idCols = ['spanid', 'parentid', 'traceid'];" -"const detailCols = []; /* Columns error, running, and latency spans all share */" +"const detailCols = ['attributes']; /* Columns error, running, and latency spans all share */" "const dateCols = ['start']; /* Categories to change to date */" "const numCols = ['duration']; /* Categories to change to num */" "const clickCols = ['error', 'running']; /* Non-latency clickable cols */" @@ -86,8 +86,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" " 'url': base_endpt + 'error/'," " 'html_id': 'name_type_detail_table'," " 'sizing': [" -" {'sz': 'sm', 'repeats': 5}," -" {'sz': 'md', 'repeats': 1}," +" {'sz': 'sm', 'repeats': 6}," " ]," " 'headings': [...idCols, ...dateCols, 'status', ...detailCols]," " 'has_subheading': true," @@ -96,8 +95,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" " 'url': base_endpt + 'running/'," " 'html_id': 'name_type_detail_table'," " 'sizing': [" -" {'sz': 'sm', 'repeats': 4}," -" {'sz': 'md', 'repeats': 1}," +" {'sz': 'sm', 'repeats': 5}," " ]," " 'headings': [...idCols, ...dateCols, ...detailCols]," " 'has_subheading': true," @@ -107,8 +105,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" " 'url': base_endpt + 'latency/'," " 'html_id': 'name_type_detail_table'," " 'sizing': [" -" {'sz': 'sm', 'repeats': 5}," -" {'sz': 'md', 'repeats': 1}," +" {'sz': 'sm', 'repeats': 6}," " ]," " 'headings': [...idCols, ...dateCols, ...numCols, ...detailCols]," " 'has_subheading': true," @@ -162,7 +159,7 @@ const char tracez_script[] = "window.onload = () => refreshData();" "/* Return formatting for an array-based value based on its header */" "const getArrayCells = (h, span) => span[h].length" " ? (span[h].map((_, i) => arrayCols[h](span, i, h))).join('')" -" : 'Empty';" +" : (Object.keys(span[h]).length ? arrayCols[h](span, h) : `${emptyContent()}`);" "" "const emptyContent = () => `(not set)`;" "" From a1ce2e952a5dc88e7bab667a30ef36c09072151b Mon Sep 17 00:00:00 2001 From: Keshav Manghat Date: Mon, 3 Aug 2020 16:31:59 +0000 Subject: [PATCH 35/37] Updated zPages example --- examples/zpages/zpages_example.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/zpages/zpages_example.cc b/examples/zpages/zpages_example.cc index 948b063f96..fb3ad5fbd3 100644 --- a/examples/zpages/zpages_example.cc +++ b/examples/zpages/zpages_example.cc @@ -17,22 +17,22 @@ int main(int argc, char* argv[]) { * Note that the webserver is destroyed after the application ends execution. */ zPages(); - auto tracer = opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(""); - + + std::cout << "This example for zPages creates a few types of spans and then " + << "creates a span every second for the duration of the application" + << "\n"; // Create a span of each type(running, completed and error) - auto running_span = tracer->StartSpan("examplespan"); + auto running_span = tracer->StartSpan("examplespan1"); + running_span->SetAttribute("attribute1", 314159); + running_span->End(); + tracer->StartSpan("examplespan")->End(); tracer->StartSpan("examplespan")->SetStatus( opentelemetry::trace::CanonicalCode::CANCELLED, "Cancelled example"); - // Change the name of the running span and end it - running_span->UpdateName("examplespan2"); - running_span->End(); - // Create another running span with a different name auto running_span2 = tracer->StartSpan("examplespan2"); - // Create a completed span every second till user stops the loop std::cout << "Presss CTRL+C to stop...\n"; while(true){ From 0524e692ee309dffc56bb298fd20bc90f3bf8613 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Mon, 3 Aug 2020 19:24:05 +0000 Subject: [PATCH 36/37] Revert "Merge master changes, formatting conflicts" This reverts commit 4fcebfc9337348bf7519e5cc95aeeb037b8f6ed8, reversing changes made to a1ce2e952a5dc88e7bab667a30ef36c09072151b. --- .github/.codecov.yaml | 2 +- WORKSPACE | 5 +- .../opentelemetry/context/runtime_context.h | 40 -- .../opentelemetry/metrics/async_instruments.h | 112 ++-- .../opentelemetry/metrics/instrument.h | 318 +++++------ api/include/opentelemetry/metrics/meter.h | 3 +- api/include/opentelemetry/metrics/noop.h | 519 +++++++++++------- .../opentelemetry/metrics/observer_result.h | 12 +- api/include/opentelemetry/metrics/provider.h | 2 +- .../opentelemetry/metrics/sync_instruments.h | 256 +++++---- api/include/opentelemetry/nostd/string_view.h | 23 +- .../opentelemetry/trace/span_context.h | 5 +- api/test/context/runtime_context_test.cc | 41 -- api/test/metrics/BUILD | 2 +- api/test/metrics/noop_instrument_test.cc | 24 +- api/test/nostd/string_view_test.cc | 2 +- api/test/trace/CMakeLists.txt | 11 +- ci/do_ci.sh | 2 + examples/simple/BUILD | 2 +- examples/simple/CMakeLists.txt | 1 - examples/simple/main.cc | 8 +- exporters/ostream/CMakeLists.txt | 10 +- .../exporters/ostream/span_exporter.h | 88 +-- exporters/ostream/src/span_exporter.cc | 73 +-- exporters/ostream/test/ostream_span_test.cc | 144 +++-- exporters/otlp/BUILD | 6 +- exporters/otlp/CMakeLists.txt | 11 +- .../exporters/otlp/otlp_exporter.h | 15 +- .../otlp/test/otlp_exporter_benchmark.cc | 14 +- .../ext/zpages/threadsafe_span_data.h | 93 ++-- .../ext/zpages/tracez_processor.h | 31 +- ext/src/zpages/BUILD | 4 +- ext/src/zpages/CMakeLists.txt | 5 +- ext/src/zpages/tracez_processor.cc | 59 +- ext/test/zpages/BUILD | 4 +- ext/test/zpages/CMakeLists.txt | 8 +- ext/test/zpages/threadsafe_span_data_test.cc | 2 +- ext/test/zpages/tracez_processor_test.cc | 306 +++++------ sdk/include/opentelemetry/sdk/metrics/TBD | 0 .../sdk/metrics/aggregator/aggregator.h | 141 ----- .../metrics/aggregator/counter_aggregator.h | 101 ---- .../sdk/metrics/aggregator/exact_aggregator.h | 164 ------ .../sdk/metrics/aggregator/gauge_aggregator.h | 138 ----- .../metrics/aggregator/histogram_aggregator.h | 197 ------- .../aggregator/min_max_sum_count_aggregator.h | 154 ------ sdk/include/opentelemetry/sdk/metrics/meter.h | 11 +- .../sdk/metrics/meter_provider.h | 5 +- .../opentelemetry/sdk/trace/recordable.h | 2 +- sdk/include/opentelemetry/sdk/trace/sampler.h | 2 +- .../sdk/trace/samplers/always_on.h | 11 +- .../sdk/trace/samplers/parent_or_else.h | 4 +- .../sdk/trace/samplers/probability.h | 11 +- sdk/include/opentelemetry/sdk/trace/tracer.h | 2 +- sdk/src/metrics/meter_provider.cc | 4 +- sdk/src/trace/CMakeLists.txt | 5 +- sdk/src/trace/samplers/parent_or_else.cc | 2 +- sdk/src/trace/samplers/probability.cc | 122 ++-- sdk/test/metrics/BUILD | 55 -- sdk/test/metrics/CMakeLists.txt | 8 +- sdk/test/metrics/counter_aggregator_test.cc | 115 ---- sdk/test/metrics/exact_aggregator_test.cc | 217 -------- sdk/test/metrics/gauge_aggregator_test.cc | 127 ----- sdk/test/metrics/histogram_aggregator_test.cc | 167 ------ sdk/test/metrics/meter_provider_sdk_test.cc | 3 +- .../min_max_sum_count_aggregator_test.cc | 203 ------- sdk/test/trace/always_off_sampler_test.cc | 22 +- sdk/test/trace/parent_or_else_sampler_test.cc | 6 +- sdk/test/trace/probability_sampler_test.cc | 4 +- tools/format.sh | 5 +- 69 files changed, 1226 insertions(+), 3045 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/metrics/TBD delete mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h delete mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h delete mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h delete mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h delete mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h delete mode 100644 sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h delete mode 100644 sdk/test/metrics/counter_aggregator_test.cc delete mode 100644 sdk/test/metrics/exact_aggregator_test.cc delete mode 100644 sdk/test/metrics/gauge_aggregator_test.cc delete mode 100644 sdk/test/metrics/histogram_aggregator_test.cc delete mode 100644 sdk/test/metrics/min_max_sum_count_aggregator_test.cc diff --git a/.github/.codecov.yaml b/.github/.codecov.yaml index 3389f63841..354ed22dd4 100644 --- a/.github/.codecov.yaml +++ b/.github/.codecov.yaml @@ -22,7 +22,7 @@ comment: # Relative file path fixing. # CI file paths must match Git file paths. -# This fix removes the "/home/runner/" prefix +# This fix removes the "/home/runner/" prefix # to coverage report file paths. fixes: - "/home/runner/::" diff --git a/WORKSPACE b/WORKSPACE index 9aff9c7c29..9a8ef94268 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -21,10 +21,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # https://github.com/bazelbuild/bazel/issues/6664 http_archive( name = "com_github_grpc_grpc", - sha256 = "d6277f77e0bb922d3f6f56c0f93292bb4cfabfc3c92b31ee5ccea0e100303612", strip_prefix = "grpc-1.28.0", urls = [ - "https://github.com/grpc/grpc/archive/v1.28.0.tar.gz", + "https://github.com/grpc/grpc/archive/v1.28.0.tar.gz", ], ) @@ -82,9 +81,9 @@ http_archive( http_archive( name = "github_nlohmann_json", - build_file = "//third_party:nlohmann_json.BUILD", sha256 = "69cc88207ce91347ea530b227ff0776db82dcb8de6704e1a3d74f4841bc651cf", urls = [ "https://github.com/nlohmann/json/releases/download/v3.6.1/include.zip", ], + build_file = "//third_party:nlohmann_json.BUILD", ) diff --git a/api/include/opentelemetry/context/runtime_context.h b/api/include/opentelemetry/context/runtime_context.h index fabd353a84..7ad3b73bdc 100644 --- a/api/include/opentelemetry/context/runtime_context.h +++ b/api/include/opentelemetry/context/runtime_context.h @@ -47,46 +47,6 @@ class RuntimeContext static RuntimeContext *context_handler_; - // Sets the Key and Value into the passed in context or if a context is not - // passed in, the RuntimeContext. - // Should be used to SetValues to the current RuntimeContext, is essentially - // equivalent to RuntimeContext::GetCurrent().SetValue(key,value). Keep in - // mind that the current RuntimeContext will not be changed, and the new - // context will be returned. - static Context SetValue(nostd::string_view key, - ContextValue value, - Context *context = nullptr) noexcept - { - Context temp_context; - if (context == nullptr) - { - temp_context = GetCurrent(); - } - else - { - temp_context = *context; - } - return temp_context.SetValue(key, value); - } - - // Returns the value associated with the passed in key and either the - // passed in context* or the runtime context if a context is not passed in. - // Should be used to get values from the current RuntimeContext, is - // essentially equivalent to RuntimeContext::GetCurrent().GetValue(key). - static ContextValue GetValue(nostd::string_view key, Context *context = nullptr) noexcept - { - Context temp_context; - if (context == nullptr) - { - temp_context = GetCurrent(); - } - else - { - temp_context = *context; - } - return temp_context.GetValue(key); - } - protected: // Provides a token with the passed in context Token CreateToken(Context context) noexcept { return Token(context); } diff --git a/api/include/opentelemetry/metrics/async_instruments.h b/api/include/opentelemetry/metrics/async_instruments.h index bfe43015f3..71504a8480 100644 --- a/api/include/opentelemetry/metrics/async_instruments.h +++ b/api/include/opentelemetry/metrics/async_instruments.h @@ -10,73 +10,77 @@ namespace metrics template class ValueObserver : virtual public AsynchronousInstrument { - + public: - ValueObserver() = default; - - ValueObserver(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void (*callback)(ObserverResult)) - {} - - /* - * Updates the instruments aggregator with the new value. The labels should - * contain the keys and values to be associated with this value. - * - * @param value is the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; - - /** - * Captures data by activating the callback function associated with the - * instrument and storing its return value. Callbacks for asynchronous - * instruments are defined during construction. - * - * @param none - * @return none - */ - virtual void run() override = 0; + ValueObserver() = default; + + ValueObserver(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void (*callback)(ObserverResult)) + {} + + /* + * Updates the instruments aggregator with the new value. The labels should + * contain the keys and values to be associated with this value. + * + * @param value is the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; + + /** + * Captures data by activating the callback function associated with the + * instrument and storing its return value. Callbacks for asynchronous + * instruments are defined during construction. + * + * @param none + * @return none + */ + virtual void run () override = 0; + }; template class SumObserver : virtual public AsynchronousInstrument { - + public: - SumObserver() = default; - - SumObserver(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void (*callback)(ObserverResult)) - {} - - virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; - - virtual void run() override = 0; + SumObserver() = default; + + SumObserver(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void (*callback)(ObserverResult)) + {} + + + virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; + + virtual void run() override = 0; + }; template class UpDownSumObserver : virtual public AsynchronousInstrument { - + public: - UpDownSumObserver() = default; - - UpDownSumObserver(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void (*callback)(ObserverResult)) - {} - - virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; - - virtual void run() override = 0; + UpDownSumObserver() = default; + + UpDownSumObserver(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void (*callback)(ObserverResult)) + {} + + virtual void observe(T value, const trace::KeyValueIterable &labels) override = 0; + + virtual void run() override = 0; + }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/instrument.h b/api/include/opentelemetry/metrics/instrument.h index 2a7ac8b6d2..9728bab8bb 100644 --- a/api/include/opentelemetry/metrics/instrument.h +++ b/api/include/opentelemetry/metrics/instrument.h @@ -1,10 +1,10 @@ #pragma once -#include #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/trace/key_value_iterable_view.h" +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics @@ -13,146 +13,146 @@ namespace metrics // Enum classes to help determine instrument types in other parts of the API enum class InstrumentKind { - Counter = 0, - UpDownCounter = 1, - ValueRecorder = 2, - ValueObserver = 3, - SumObserver = 4, - UpDownSumObserver = 5, + Counter = 0, + UpDownCounter = 1, + ValueRecorder = 2, + ValueObserver = 3, + SumObserver = 4, + UpDownSumObserver = 5, }; class Instrument { - + public: - // Note that Instruments should be created using the Meter class. - // Please refer to meter.h for documentation. - Instrument() = default; - - /** - * Base class constructor for all other instrument types. Whether or not - * an instrument is synchronous or bound, it requires a name, description, - * unit, and enabled flag. - * - * @param name is the identifier of the instrumenting library - * @param description explains what the metric captures - * @param unit specifies the data type held in the instrument - * @param enabled determines if the metric is currently capturing data - * @return Instrument type with the specified attirbutes - */ - Instrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled) - {} - - // Returns true if the instrument is enabled and collecting data - virtual bool IsEnabled() = 0; - - // Return the instrument name - virtual nostd::string_view GetName() = 0; - - // Return the instrument description - virtual nostd::string_view GetDescription() = 0; - - // Return the insrument's units of measurement - virtual nostd::string_view GetUnits() = 0; - - // Return the intrument's kind - virtual InstrumentKind GetKind() = 0; - - virtual ~Instrument() = default; + // Note that Instruments should be created using the Meter class. + // Please refer to meter.h for documentation. + Instrument() = default; + + /** + * Base class constructor for all other instrument types. Whether or not + * an instrument is synchronous or bound, it requires a name, description, + * unit, and enabled flag. + * + * @param name is the identifier of the instrumenting library + * @param description explains what the metric captures + * @param unit specifies the data type held in the instrument + * @param enabled determines if the metric is currently capturing data + * @return Instrument type with the specified attirbutes + */ + Instrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled) + {} + + // Returns true if the instrument is enabled and collecting data + virtual bool IsEnabled() = 0; + + // Return the instrument name + virtual nostd::string_view GetName() = 0; + + // Return the instrument description + virtual nostd::string_view GetDescription() = 0; + + // Return the insrument's units of measurement + virtual nostd::string_view GetUnits() = 0; + + // Return the intrument's kind + virtual InstrumentKind GetKind() = 0; + + virtual ~Instrument() = default; }; template class BoundSynchronousInstrument : virtual public Instrument { - + public: - BoundSynchronousInstrument() = default; - - BoundSynchronousInstrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /** - * Frees the resources associated with this Bound Instrument. - * The Metric from which this instrument was created is not impacted. - * - * @param none - * @return void - */ - virtual void unbind() {} - - /** - * Incremements the reference count of this bound object when a new instance is - * either created or the same instance is returned as a result of binding - * - * @param none - * @return void - */ - virtual void inc_ref() {} - - /** - * Return the object's current reference count. This information is used to remove - * stale objects from instrument registries. - */ - virtual int get_ref() { return 0; } - - /** - * Records a single synchronous metric event; a call to the aggregator - * Since this is a bound synchronous instrument, labels are not required in * metric capture - * calls. - * - * @param value is the numerical representation of the metric being captured - * @return void - */ - virtual void update(T value) {} + BoundSynchronousInstrument() = default; + + BoundSynchronousInstrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /** + * Frees the resources associated with this Bound Instrument. + * The Metric from which this instrument was created is not impacted. + * + * @param none + * @return void + */ + virtual void unbind() {} + + /** + * Incremements the reference count of this bound object when a new instance is + * either created or the same instance is returned as a result of binding + * + * @param none + * @return void + */ + virtual void inc_ref () {} + + /** + * Return the object's current reference count. This information is used to remove + * stale objects from instrument registries. + */ + virtual int get_ref() { + return 0; + } + + /** + * Records a single synchronous metric event; a call to the aggregator + * Since this is a bound synchronous instrument, labels are not required in * metric capture + * calls. + * + * @param value is the numerical representation of the metric being captured + * @return void + */ + virtual void update(T value) {} }; template class SynchronousInstrument : virtual public Instrument { - + public: - SynchronousInstrument() = default; - - SynchronousInstrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled) - {} - - /** - * Returns a Bound Instrument associated with the specified labels. * Multiples requests - * with the same set of labels may return the same Bound Instrument instance. - * - * It is recommended that callers keep a reference to the Bound Instrument - * instead of repeatedly calling this operation. - * - * @param labels the set of labels, as key-value pairs - * @return a Bound Instrument - */ - virtual nostd::shared_ptr> bind( - const trace::KeyValueIterable &labels) - { - return nostd::shared_ptr>(); - } - - /** - * Records a single synchronous metric event. - * Since this is an unbound synchronous instrument, labels are required in * metric capture - * calls. - * - * update can be used in instruments with both add or record since it simply - * activated the aggregator - * - * @param labels the set of labels, as key-value pairs - * @param value is the numerical representation of the metric being captured - * @return void - */ - virtual void update(T value, const trace::KeyValueIterable &labels) = 0; + SynchronousInstrument() = default; + + SynchronousInstrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled) + { } + + /** + * Returns a Bound Instrument associated with the specified labels. * Multiples requests + * with the same set of labels may return the same Bound Instrument instance. + * + * It is recommended that callers keep a reference to the Bound Instrument + * instead of repeatedly calling this operation. + * + * @param labels the set of labels, as key-value pairs + * @return a Bound Instrument + */ + virtual nostd::shared_ptr> bind(const trace::KeyValueIterable &labels) { + return nostd::shared_ptr>(); + } + + /** + * Records a single synchronous metric event. + * Since this is an unbound synchronous instrument, labels are required in * metric capture + * calls. + * + * update can be used in instruments with both add or record since it simply + * activated the aggregator + * + * @param labels the set of labels, as key-value pairs + * @param value is the numerical representation of the metric being captured + * @return void + */ + virtual void update(T value, const trace::KeyValueIterable &labels) = 0; }; template @@ -161,43 +161,43 @@ class ObserverResult; template class AsynchronousInstrument : virtual public Instrument { - + public: - AsynchronousInstrument() = default; - - AsynchronousInstrument(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled, - void(callback)(ObserverResult)) - {} - - /** - * Captures data through a manual call rather than the automatic collection process instituted - * in the run function. Asynchronous instruments are generally expected to obtain data from - * their callbacks rather than direct calls. This function is used by the callback to store data. - * - * @param value is the numerical representation of the metric being captured - * @param labels is the numerical representation of the metric being captured - * @return none - */ - virtual void observe(T value, const trace::KeyValueIterable &labels) = 0; - - /** - * Captures data by activating the callback function associated with the - * instrument and storing its return value. Callbacks for asynchronous - * instruments are defined during construction. - * - * @param none - * @return none - */ - virtual void run() = 0; - + AsynchronousInstrument() = default; + + AsynchronousInstrument(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled, + void(callback)(ObserverResult)) + {} + + /** + * Captures data through a manual call rather than the automatic collection process instituted + * in the run function. Asynchronous instruments are generally expected to obtain data from + * their callbacks rather than direct calls. This function is used by the callback to store data. + * + * @param value is the numerical representation of the metric being captured + * @param labels is the numerical representation of the metric being captured + * @return none + */ + virtual void observe (T value, const trace::KeyValueIterable &labels) = 0; + + /** + * Captures data by activating the callback function associated with the + * instrument and storing its return value. Callbacks for asynchronous + * instruments are defined during construction. + * + * @param none + * @return none + */ + virtual void run() = 0; + protected: - // Callback function which takes a pointer to an Asynchronous instrument (this) type which is - // stored in an observer result type and returns nothing. This function calls the instrument's - // observe. - void (*callback_)(ObserverResult); + // Callback function which takes a pointer to an Asynchronous instrument (this) type which is + // stored in an observer result type and returns nothing. This function calls the instrument's + // observe. + void (*callback_)(ObserverResult); }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/meter.h b/api/include/opentelemetry/metrics/meter.h index 19439da6df..42c189a6dd 100644 --- a/api/include/opentelemetry/metrics/meter.h +++ b/api/include/opentelemetry/metrics/meter.h @@ -10,8 +10,9 @@ class Meter { public: Meter() = default; + }; -} // namespace metrics +} // namespace metrics OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/metrics/noop.h b/api/include/opentelemetry/metrics/noop.h index b5e8988f92..3695277410 100644 --- a/api/include/opentelemetry/metrics/noop.h +++ b/api/include/opentelemetry/metrics/noop.h @@ -4,25 +4,25 @@ // This file is part of the internal implementation of OpenTelemetry. Nothing in this file should be // used directly. Please refer to meter.h for documentation on these interfaces. -#include "opentelemetry/metrics/async_instruments.h" +#include "opentelemetry/version.h" #include "opentelemetry/metrics/instrument.h" #include "opentelemetry/metrics/meter.h" #include "opentelemetry/metrics/meter_provider.h" #include "opentelemetry/metrics/sync_instruments.h" +#include "opentelemetry/metrics/async_instruments.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" -#include "opentelemetry/version.h" #include + OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics { /** * No-op implementation of a MeterProvider. */ -class NoopMeter final : public Meter, public std::enable_shared_from_this -{}; +class NoopMeter final : public Meter, public std::enable_shared_from_this {}; class NoopMeterProvider final : public opentelemetry::metrics::MeterProvider { @@ -46,262 +46,359 @@ class NoopMeterProvider final : public opentelemetry::metrics::MeterProvider template class NoopValueObserver : public ValueObserver { - + public: - NoopValueObserver(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/, - void (*callback)(ObserverResult)) - {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual void observe(T value, const trace::KeyValueIterable &labels) override {} - - virtual void run() override {} - - virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } + NoopValueObserver(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/, + void (*callback)(ObserverResult)) {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual void observe(T value, const trace::KeyValueIterable &labels) override {} + + virtual void run() override {} + + virtual InstrumentKind GetKind() override { + return InstrumentKind::Counter; + } + }; + template class NoopSumObserver : public SumObserver { - + public: - NoopSumObserver(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/, - void (*callback)(ObserverResult)) - {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual void observe(T value, const trace::KeyValueIterable &labels) override {} - - virtual void run() override {} - - virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } + NoopSumObserver(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/, + void (*callback)(ObserverResult)) + {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual void observe(T value, const trace::KeyValueIterable &labels) override {} + + virtual void run() override {} + + virtual InstrumentKind GetKind() override { + return InstrumentKind::Counter; + } }; + template class NoopUpDownSumObserver : public UpDownSumObserver { - + public: - NoopUpDownSumObserver(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/, - void (*callback)(ObserverResult)) - {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual void observe(T value, const trace::KeyValueIterable &labels) override {} - - virtual void run() override {} - - virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } + NoopUpDownSumObserver(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/, + void (*callback)(ObserverResult)) + {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual void observe(T value, const trace::KeyValueIterable &labels) override {} + + virtual void run() override {} + + virtual InstrumentKind GetKind() override { + return InstrumentKind::Counter; + } }; + template class BoundNoopCounter : public BoundCounter { - + public: - BoundNoopCounter() = default; - - BoundNoopCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - virtual void add(T value) override {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } + BoundNoopCounter() = default; + + BoundNoopCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + virtual void add(T value) override {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual InstrumentKind GetKind() override { + return InstrumentKind::Counter; + } + }; template class NoopCounter : public Counter { - + public: - NoopCounter() = default; - - NoopCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - nostd::shared_ptr> bindNoopCounter(const trace::KeyValueIterable & /*labels*/) - { - return nostd::shared_ptr>(new BoundNoopCounter()); - } - - virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; } + NoopCounter() = default; + + NoopCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + nostd::shared_ptr> bindNoopCounter(const trace::KeyValueIterable & /*labels*/) + { + return nostd::shared_ptr>(new BoundNoopCounter()); + } + + virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual InstrumentKind GetKind() override { + return InstrumentKind::Counter; + } + }; template class BoundNoopUpDownCounter : public BoundUpDownCounter { - + public: - BoundNoopUpDownCounter() = default; - - BoundNoopUpDownCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - virtual void add(T value) override {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual InstrumentKind GetKind() override { return InstrumentKind::UpDownCounter; } + BoundNoopUpDownCounter() = default; + + BoundNoopUpDownCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + virtual void add(T value) override {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual InstrumentKind GetKind() override { + return InstrumentKind::UpDownCounter; + } + }; template class NoopUpDownCounter : public UpDownCounter { - + public: - NoopUpDownCounter() = default; - - NoopUpDownCounter(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - nostd::shared_ptr> bindNoopUpDownCounter( - const trace::KeyValueIterable & /*labels*/) - { - return nostd::shared_ptr>(new BoundNoopUpDownCounter()); - } - - virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual InstrumentKind GetKind() override { return InstrumentKind::UpDownCounter; } + NoopUpDownCounter() = default; + + NoopUpDownCounter(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + nostd::shared_ptr> bindNoopUpDownCounter(const trace::KeyValueIterable & /*labels*/) + { + return nostd::shared_ptr>(new BoundNoopUpDownCounter()); + } + + virtual void add(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual InstrumentKind GetKind() override { + return InstrumentKind::UpDownCounter; + } }; + template class BoundNoopValueRecorder : public BoundValueRecorder { - + public: - BoundNoopValueRecorder() = default; - - BoundNoopValueRecorder(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - virtual void record(T value) override {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual InstrumentKind GetKind() override { return InstrumentKind::ValueRecorder; } + BoundNoopValueRecorder() = default; + + BoundNoopValueRecorder(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + virtual void record(T value) override {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual InstrumentKind GetKind() override { + return InstrumentKind::ValueRecorder; + } }; template class NoopValueRecorder : public ValueRecorder { - + public: - NoopValueRecorder() = default; - - NoopValueRecorder(nostd::string_view /*name*/, - nostd::string_view /*description*/, - nostd::string_view /*unit*/, - bool /*enabled*/) - {} - - nostd::shared_ptr> bindNoopValueRecorder( - const trace::KeyValueIterable & /*labels*/) - { - return nostd::shared_ptr>(new BoundNoopValueRecorder()); - } - - virtual void record(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} - - virtual bool IsEnabled() override { return false; } - - virtual nostd::string_view GetName() override { return nostd::string_view(""); } - - virtual nostd::string_view GetDescription() override { return nostd::string_view(""); } - - virtual nostd::string_view GetUnits() override { return nostd::string_view(""); } - - virtual InstrumentKind GetKind() override { return InstrumentKind::ValueRecorder; } + NoopValueRecorder() = default; + + NoopValueRecorder(nostd::string_view /*name*/, + nostd::string_view /*description*/, + nostd::string_view /*unit*/, + bool /*enabled*/) + {} + + nostd::shared_ptr> bindNoopValueRecorder(const trace::KeyValueIterable & /*labels*/) + { + return nostd::shared_ptr>(new BoundNoopValueRecorder()); + } + + virtual void record(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual void update(T value, const trace::KeyValueIterable & /*labels*/) override {} + + virtual bool IsEnabled() override { + return false; + } + + virtual nostd::string_view GetName() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetDescription() override { + return nostd::string_view(""); + } + + virtual nostd::string_view GetUnits() override { + return nostd::string_view(""); + } + + virtual InstrumentKind GetKind() override { + return InstrumentKind::ValueRecorder; + } + }; -} // namespace metrics + +} // namespace metrics OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/metrics/observer_result.h b/api/include/opentelemetry/metrics/observer_result.h index a16b5a3815..5b675092eb 100644 --- a/api/include/opentelemetry/metrics/observer_result.h +++ b/api/include/opentelemetry/metrics/observer_result.h @@ -21,15 +21,15 @@ class ObserverResult public: ObserverResult() = default; - ObserverResult(AsynchronousInstrument *instrument) : instrument_(instrument) {} + ObserverResult(AsynchronousInstrument * instrument): instrument_(instrument) {} - virtual void observe(T value, const trace::KeyValueIterable &labels) - { - instrument_->observe(value, labels); + virtual void observe(T value, const trace::KeyValueIterable &labels) { + instrument_->observe(value, labels); } - + private: - AsynchronousInstrument *instrument_; + AsynchronousInstrument * instrument_; + }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/provider.h b/api/include/opentelemetry/metrics/provider.h index 8559562d8d..be79611e1e 100644 --- a/api/include/opentelemetry/metrics/provider.h +++ b/api/include/opentelemetry/metrics/provider.h @@ -38,7 +38,7 @@ class Provider { while (GetLock().test_and_set(std::memory_order_acquire)) ; - GetProvider() = tp; + GetProvider() = tp; GetLock().clear(std::memory_order_release); } diff --git a/api/include/opentelemetry/metrics/sync_instruments.h b/api/include/opentelemetry/metrics/sync_instruments.h index 8823d83e4d..79f3a45097 100644 --- a/api/include/opentelemetry/metrics/sync_instruments.h +++ b/api/include/opentelemetry/metrics/sync_instruments.h @@ -9,167 +9,163 @@ namespace metrics template class BoundCounter : virtual public BoundSynchronousInstrument { - + public: - BoundCounter() = default; - - BoundCounter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /* - * Add adds the value to the counter's sum. The labels are already linked * to the instrument - * and are not specified. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value) = 0; + BoundCounter() = default; + + BoundCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /* + * Add adds the value to the counter's sum. The labels are already linked * to the instrument + * and are not specified. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value) = 0; }; template class Counter : virtual public SynchronousInstrument { - + public: - Counter() = default; - - Counter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled) - {} - - /* - * Bind creates a bound instrument for this counter. The labels are - * associated with values recorded via subsequent calls to Record. - * - * @param labels the set of labels, as key-value pairs. - * @return a BoundIntCounter tied to the specified labels - */ - virtual nostd::shared_ptr> bindCounter(const trace::KeyValueIterable &labels) - { - return nostd::shared_ptr>(); - } - - /* - * Add adds the value to the counter's sum. The labels should contain - * the keys and values to be associated with this value. Counters only * accept positive - * valued updates. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value, const trace::KeyValueIterable &labels) = 0; - - virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; + Counter() = default; + + Counter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled) {} + + /* + * Bind creates a bound instrument for this counter. The labels are + * associated with values recorded via subsequent calls to Record. + * + * @param labels the set of labels, as key-value pairs. + * @return a BoundIntCounter tied to the specified labels + */ + virtual nostd::shared_ptr> bindCounter(const trace::KeyValueIterable &labels) { + return nostd::shared_ptr>(); + } + + /* + * Add adds the value to the counter's sum. The labels should contain + * the keys and values to be associated with this value. Counters only * accept positive + * valued updates. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value, const trace::KeyValueIterable &labels) = 0; + + virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; }; template class BoundUpDownCounter : virtual public BoundSynchronousInstrument { - + public: - BoundUpDownCounter() = default; - - BoundUpDownCounter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /* - * Add adds the value to the counter's sum. The labels are already linked to * the instrument and - * do not need to specified again. UpDownCounters can accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value) = 0; + BoundUpDownCounter() = default; + + BoundUpDownCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /* + * Add adds the value to the counter's sum. The labels are already linked to * the instrument and + * do not need to specified again. UpDownCounters can accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value) = 0; }; template class UpDownCounter : virtual public SynchronousInstrument { - + public: - UpDownCounter() = default; - - UpDownCounter(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - virtual nostd::shared_ptr> bindUpDownCounter( - const trace::KeyValueIterable &labels) - { - return nostd::shared_ptr>(); - } - - /* - * Add adds the value to the counter's sum. The labels should contain - * the keys and values to be associated with this value. UpDownCounters can - * accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void add(T value, const trace::KeyValueIterable &labels) = 0; - - virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; + UpDownCounter() = default; + + UpDownCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + virtual nostd::shared_ptr> bindUpDownCounter(const trace::KeyValueIterable &labels) + { + return nostd::shared_ptr>(); + } + + /* + * Add adds the value to the counter's sum. The labels should contain + * the keys and values to be associated with this value. UpDownCounters can + * accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void add(T value, const trace::KeyValueIterable &labels) = 0; + + virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; }; template class BoundValueRecorder : virtual public BoundSynchronousInstrument { - + public: - BoundValueRecorder() = default; - - BoundValueRecorder(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - /* - * Records the value by summing it with previous measurements and checking * previously stored - * minimum and maximum values. The labels associated with * new values are already linked to the - * instrument as it is bound. * ValueRecorders can accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - */ - virtual void record(T value) = 0; + BoundValueRecorder() = default; + + BoundValueRecorder(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + /* + * Records the value by summing it with previous measurements and checking * previously stored + * minimum and maximum values. The labels associated with * new values are already linked to the + * instrument as it is bound. * ValueRecorders can accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + */ + virtual void record(T value) = 0; }; + template class ValueRecorder : virtual public SynchronousInstrument { - + public: - ValueRecorder() = default; - - ValueRecorder(nostd::string_view name, - nostd::string_view description, - nostd::string_view unit, - bool enabled); - - virtual nostd::shared_ptr> bindValueRecorder( - const trace::KeyValueIterable &labels) - { - return nostd::shared_ptr>(); - } - - /* - * Records the value by summing it with previous measurements and checking * previously stored - * minimum and maximum values. The labels should contain the keys and values to be associated with - * this value. ValueRecorders can accept positive and negative values. - * - * @param value the numerical representation of the metric being captured - * @param labels the set of labels, as key-value pairs - */ - virtual void record(T value, const trace::KeyValueIterable &labels) = 0; - - virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; + ValueRecorder() = default; + + ValueRecorder(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit, + bool enabled); + + virtual nostd::shared_ptr> bindValueRecorder(const trace::KeyValueIterable &labels){ + return nostd::shared_ptr>(); + } + + /* + * Records the value by summing it with previous measurements and checking * previously stored + * minimum and maximum values. The labels should contain the keys and values to be associated with + * this value. ValueRecorders can accept positive and negative values. + * + * @param value the numerical representation of the metric being captured + * @param labels the set of labels, as key-value pairs + */ + virtual void record(T value, const trace::KeyValueIterable &labels) = 0; + + virtual void update(T value, const trace::KeyValueIterable &labels) override = 0; }; } // namespace metrics diff --git a/api/include/opentelemetry/nostd/string_view.h b/api/include/opentelemetry/nostd/string_view.h index 315d038b3f..e947d23259 100644 --- a/api/include/opentelemetry/nostd/string_view.h +++ b/api/include/opentelemetry/nostd/string_view.h @@ -71,7 +71,7 @@ class string_view int compare(string_view v) const noexcept { size_type len = std::min(size(), v.size()); - int result = Traits::compare(data(), v.data(), len); + int result = Traits::compare(data(), v.data(), len); if (result == 0) result = size() == v.size() ? 0 : (size() < v.size() ? -1 : 1); return result; @@ -82,16 +82,15 @@ class string_view return substr(pos1, count1).compare(v); }; - int compare(size_type pos1, - size_type count1, - string_view v, - size_type pos2, - size_type count2) const + int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const { return substr(pos1, count1).compare(v.substr(pos2, count2)); }; - int compare(const char *s) const { return compare(string_view(s)); }; + int compare(const char *s) const + { + return compare(string_view(s)); + }; int compare(size_type pos1, size_type count1, const char *s) const { @@ -103,9 +102,15 @@ class string_view return substr(pos1, count1).compare(string_view(s, count2)); }; - bool operator<(const string_view v) const noexcept { return compare(v) < 0; } + bool operator<(const string_view v) const noexcept + { + return compare(v) < 0; + } - bool operator>(const string_view v) const noexcept { return compare(v) > 0; } + bool operator>(const string_view v) const noexcept + { + return compare(v) > 0; + } private: // Note: uses the same binary layout as libstdc++'s std::string_view diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h index 57b6a72e2e..fc04ce17e6 100644 --- a/api/include/opentelemetry/trace/span_context.h +++ b/api/include/opentelemetry/trace/span_context.h @@ -39,9 +39,8 @@ class SpanContext final * @param has_remote_parent a required parameter specifying if this context has * a remote parent */ - SpanContext(bool sampled_flag, bool has_remote_parent) - : trace_flags_(trace_api::TraceFlags((uint8_t)sampled_flag)), - remote_parent_(has_remote_parent){}; + SpanContext(bool sampled_flag, bool has_remote_parent) : + trace_flags_(trace_api::TraceFlags((uint8_t) sampled_flag)), remote_parent_(has_remote_parent) {}; // @returns the trace_flags associated with this span_context const trace_api::TraceFlags &trace_flags() const noexcept { return trace_flags_; } diff --git a/api/test/context/runtime_context_test.cc b/api/test/context/runtime_context_test.cc index 5c0dc565d4..b70d69dce8 100644 --- a/api/test/context/runtime_context_test.cc +++ b/api/test/context/runtime_context_test.cc @@ -59,44 +59,3 @@ TEST(RuntimeContextTest, ThreeAttachDetach) EXPECT_TRUE(context::RuntimeContext::Detach(foo_context_token)); EXPECT_TRUE(context::RuntimeContext::Detach(test_context_token)); } - -// Tests that SetValue returns a context with the passed in data and the -// RuntimeContext data when a context is not passed into the -// RuntimeContext::SetValue method. -TEST(RuntimeContextTest, SetValueRuntimeContext) -{ - context::Context foo_context = context::Context("foo_key", (int64_t)596); - context::RuntimeContext::Token old_context_token = context::RuntimeContext::Attach(foo_context); - context::Context test_context = context::RuntimeContext::SetValue("test_key", (int64_t)123); - EXPECT_EQ(nostd::get(test_context.GetValue("test_key")), 123); - EXPECT_EQ(nostd::get(test_context.GetValue("foo_key")), 596); -} - -// Tests that SetValue returns a context with the passed in data and the -// passed in context data when a context* is passed into the -// RuntimeContext::SetValue method. -TEST(RuntimeContextTest, SetValueOtherContext) -{ - context::Context foo_context = context::Context("foo_key", (int64_t)596); - context::Context test_context = - context::RuntimeContext::SetValue("test_key", (int64_t)123, &foo_context); - EXPECT_EQ(nostd::get(test_context.GetValue("test_key")), 123); - EXPECT_EQ(nostd::get(test_context.GetValue("foo_key")), 596); -} - -// Tests that SetValue returns the ContextValue associated with the -// passed in string and the current Runtime Context -TEST(RuntimeContextTest, GetValueRuntimeContext) -{ - context::Context foo_context = context::Context("foo_key", (int64_t)596); - context::RuntimeContext::Token old_context_token = context::RuntimeContext::Attach(foo_context); - EXPECT_EQ(nostd::get(context::RuntimeContext::GetValue("foo_key")), 596); -} - -// Tests that SetValue returns the ContextValue associated with the -// passed in string and the passed in context -TEST(RuntimeContextTest, GetValueOtherContext) -{ - context::Context foo_context = context::Context("foo_key", (int64_t)596); - EXPECT_EQ(nostd::get(context::RuntimeContext::GetValue("foo_key", &foo_context)), 596); -} diff --git a/api/test/metrics/BUILD b/api/test/metrics/BUILD index a56dc3fcd0..08cd98cf8e 100644 --- a/api/test/metrics/BUILD +++ b/api/test/metrics/BUILD @@ -21,4 +21,4 @@ cc_test( "//api", "@com_google_googletest//:gtest_main", ], -) +) \ No newline at end of file diff --git a/api/test/metrics/noop_instrument_test.cc b/api/test/metrics/noop_instrument_test.cc index 5e53599f50..46f4babe42 100644 --- a/api/test/metrics/noop_instrument_test.cc +++ b/api/test/metrics/noop_instrument_test.cc @@ -1,8 +1,8 @@ #include #include -#include #include #include "opentelemetry/metrics/noop.h" +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace metrics @@ -11,7 +11,7 @@ namespace metrics void noopIntCallback(ObserverResult result) { std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; result.observe(1, labelkv); result.observe(-1, labelkv); } @@ -19,7 +19,7 @@ void noopIntCallback(ObserverResult result) void noopDoubleCallback(ObserverResult result) { std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; result.observe(1.5, labelkv); result.observe(-1.5, labelkv); } @@ -31,7 +31,7 @@ TEST(ValueObserver, Observe) NoopValueObserver beta("test", "none", "unitless", true, &noopDoubleCallback); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.observe(1, labelkv); beta.observe(1.5, labelkv); @@ -44,7 +44,7 @@ TEST(SumObserver, DefaultConstruction) NoopSumObserver beta("test", "none", "unitless", true, &noopDoubleCallback); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.observe(1, labelkv); beta.observe(1.5, labelkv); @@ -57,7 +57,7 @@ TEST(UpDownSumObserver, DefaultConstruction) NoopUpDownSumObserver beta("test", "none", "unitless", true, &noopDoubleCallback); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.observe(1, labelkv); beta.observe(1.0, labelkv); @@ -71,7 +71,7 @@ TEST(Counter, DefaultConstruction) NoopCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.bind(labelkv); @@ -88,7 +88,7 @@ TEST(Counter, Add) NoopCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.add(1, labelkv); beta.add(1.5, labelkv); @@ -109,7 +109,7 @@ TEST(UpDownCounter, DefaultConstruction) NoopUpDownCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.bind(labelkv); @@ -126,7 +126,7 @@ TEST(UpDownCounter, Add) NoopUpDownCounter beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.add(1, labelkv); beta.add(1.5, labelkv); @@ -149,7 +149,7 @@ TEST(ValueRecorder, DefaultConstruction) NoopValueRecorder beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.bind(labelkv); @@ -166,7 +166,7 @@ TEST(ValueRecorder, Record) NoopValueRecorder beta("other", "none", "unitless", true); std::map labels = {{"key", "value"}}; - auto labelkv = trace::KeyValueIterableView{labels}; + auto labelkv = trace::KeyValueIterableView{labels}; alpha.record(1, labelkv); beta.record(1.5, labelkv); diff --git a/api/test/nostd/string_view_test.cc b/api/test/nostd/string_view_test.cc index 364410a312..074d3bee49 100644 --- a/api/test/nostd/string_view_test.cc +++ b/api/test/nostd/string_view_test.cc @@ -95,7 +95,7 @@ TEST(StringViewTest, Compare) TEST(StringViewTest, MapKeyOrdering) { std::map m = {{"bbb", 2}, {"aaa", 1}, {"ccc", 3}}; - size_t i = 1; + size_t i = 1; for (const auto &kv : m) { EXPECT_EQ(kv.second, i); diff --git a/api/test/trace/CMakeLists.txt b/api/test/trace/CMakeLists.txt index 16cef9bc6d..3439146f7a 100644 --- a/api/test/trace/CMakeLists.txt +++ b/api/test/trace/CMakeLists.txt @@ -1,12 +1,5 @@ -foreach( - testname - key_value_iterable_view_test - noop_test - provider_test - span_id_test - trace_id_test - trace_flags_test - span_context_test) +foreach(testname key_value_iterable_view_test noop_test provider_test + span_id_test trace_id_test trace_flags_test span_context_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index b394de03c8..b6d23f763f 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -107,6 +107,8 @@ elif [[ "$1" == "benchmark" ]]; then exit 0 elif [[ "$1" == "format" ]]; then tools/format.sh + # normalize file endings according to .gitattributes + git add --renormalize . CHANGED="$(git ls-files --modified)" if [[ ! -z "$CHANGED" ]]; then echo "The following files have changes:" diff --git a/examples/simple/BUILD b/examples/simple/BUILD index a8e843e29d..df6ad8ecc7 100644 --- a/examples/simple/BUILD +++ b/examples/simple/BUILD @@ -18,8 +18,8 @@ cc_binary( ], deps = [ ":foo_library", - "//api", "//exporters/ostream:ostream_span_exporter", + "//api", "//sdk/src/trace", ], ) diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt index 8b13789179..e69de29bb2 100644 --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -1 +0,0 @@ - diff --git a/examples/simple/main.cc b/examples/simple/main.cc index 485d31c2ec..50cbc8fac7 100644 --- a/examples/simple/main.cc +++ b/examples/simple/main.cc @@ -3,19 +3,17 @@ #include "opentelemetry/trace/provider.h" // Using an exporter that simply dumps span data to stdout. -#include "foo_library/foo_library.h" #include "opentelemetry/exporters/ostream/span_exporter.h" +#include "foo_library/foo_library.h" namespace { void initTracer() { - auto exporter = std::unique_ptr( - new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); - auto provider = nostd::shared_ptr( - new sdktrace::TracerProvider(processor)); + auto provider = nostd::shared_ptr(new sdktrace::TracerProvider(processor)); // Set the global trace provider opentelemetry::trace::Provider::SetTracerProvider(provider); } diff --git a/exporters/ostream/CMakeLists.txt b/exporters/ostream/CMakeLists.txt index ebc595ed21..54c93bc1aa 100644 --- a/exporters/ostream/CMakeLists.txt +++ b/exporters/ostream/CMakeLists.txt @@ -3,8 +3,8 @@ include_directories(include) add_library(opentelemetry_exporter_ostream_span src/span_exporter.cc) add_executable(ostream_span_test test/ostream_span_test.cc) -target_link_libraries( - ostream_span_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_ostream_span) -gtest_add_tests(TARGET ostream_span_test TEST_PREFIX exporter. TEST_LIST - ostream_span_test) +target_link_libraries(ostream_span_test + ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_ostream_span) +gtest_add_tests(TARGET ostream_span_test TEST_PREFIX exporter. TEST_LIST ostream_span_test) diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h index c20ba7d362..a4dd83a597 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h @@ -1,8 +1,8 @@ #pragma once -#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/version.h" #include @@ -20,15 +20,16 @@ namespace trace /** * The OStreamSpanExporter exports span data through an ostream - */ +*/ class OStreamSpanExporter final : public sdktrace::SpanExporter { public: - /** - * Create an OStreamSpanExporter. This constructor takes in a reference to an ostream that the - * export() function will send span data into. - * The default ostream is set to stdout - */ + +/** + * Create an OStreamSpanExporter. This constructor takes in a reference to an ostream that the + * export() function will send span data into. + * The default ostream is set to stdout + */ explicit OStreamSpanExporter(std::ostream &sout = std::cout) noexcept; std::unique_ptr MakeRecordable() noexcept override; @@ -43,28 +44,29 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter bool isShutdown_ = false; // Mapping status number to the string from api/include/opentelemetry/trace/canonical_code.h - std::map statusMap{{0, "OK"}, - {1, "CANCELLED"}, - {2, "UNKNOWN"}, - {3, "INVALID_ARGUMENT"}, - {4, "DEADLINE_EXCEEDED"}, - {5, "NOT_FOUND"}, - {6, "ALREADY_EXISTS"}, - {7, "PERMISSION_DENIED"}, - {8, "RESOURCE_EXHAUSTED"}, - {9, "FAILED_PRECONDITION"}, - {10, "ABORTED"}, - {11, "OUT_OF_RANGE"}, - {12, "UNIMPLEMENTED"}, - {13, "INTERNAL"}, - {14, "UNAVAILABLE"}, - {15, "DATA_LOSS"}, - {16, "UNAUTHENTICATED"}}; + std::map statusMap { + {0, "OK"}, + {1, "CANCELLED"}, + {2, "UNKNOWN"}, + {3, "INVALID_ARGUMENT"}, + {4, "DEADLINE_EXCEEDED"}, + {5, "NOT_FOUND"}, + {6, "ALREADY_EXISTS"}, + {7, "PERMISSION_DENIED"}, + {8, "RESOURCE_EXHAUSTED"}, + {9, "FAILED_PRECONDITION"}, + {10, "ABORTED"}, + {11, "OUT_OF_RANGE"}, + {12, "UNIMPLEMENTED"}, + {13, "INTERNAL"}, + {14, "UNAVAILABLE"}, + {15, "DATA_LOSS"}, + {16, "UNAUTHENTICATED"} + }; /* - print_array and print_value are used to print out the value of an attribute within a vector. - These values are held in a variant which makes the process of printing them much more - complicated. + print_array and print_value are used to print out the value of an attribute within a vector. These values + are held in a variant which makes the process of printing them much more complicated. */ template @@ -76,7 +78,7 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter size_t sz = s.size(); for (auto v : s) { - sout_ << v; + sout_ << v; if (i != sz) sout_ << ','; i++; @@ -86,43 +88,43 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter void print_value(sdktrace::SpanDataAttributeValue &value) { - if (nostd::holds_alternative(value)) + if(nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if (nostd::holds_alternative(value)) + else if(nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if (nostd::holds_alternative(value)) + else if(nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if (nostd::holds_alternative(value)) + else if(nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if (nostd::holds_alternative(value)) + else if(nostd::holds_alternative(value)) { sout_ << nostd::get(value); } - else if (nostd::holds_alternative>(value)) + else if(nostd::holds_alternative>(value)) { print_array(value); } - else if (nostd::holds_alternative>(value)) + else if(nostd::holds_alternative>(value)) { print_array(value); } - else if (nostd::holds_alternative>(value)) + else if(nostd::holds_alternative>(value)) { print_array(value); } - else if (nostd::holds_alternative>(value)) + else if(nostd::holds_alternative>(value)) { print_array(value); } - else if (nostd::holds_alternative>(value)) + else if(nostd::holds_alternative>(value)) { print_array(value); } @@ -131,8 +133,8 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter void printAttributes(std::unordered_map map) { int size = map.size(); - int i = 1; - for (auto kv : map) + int i = 1; + for(auto kv : map) { sout_ << kv.first << ": "; print_value(kv.second); @@ -141,8 +143,10 @@ class OStreamSpanExporter final : public sdktrace::SpanExporter sout_ << ", "; i++; } + } + }; -} // namespace trace -} // namespace exporter +} +} OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/ostream/src/span_exporter.cc b/exporters/ostream/src/span_exporter.cc index 3837d7110b..7e2e4237ab 100644 --- a/exporters/ostream/src/span_exporter.cc +++ b/exporters/ostream/src/span_exporter.cc @@ -10,60 +10,61 @@ namespace exporter { namespace trace { -OStreamSpanExporter::OStreamSpanExporter(std::ostream &sout) noexcept : sout_(sout) {} +OStreamSpanExporter::OStreamSpanExporter(std::ostream &sout) noexcept + : sout_(sout) {} -std::unique_ptr OStreamSpanExporter::MakeRecordable() noexcept +std::unique_ptr OStreamSpanExporter::MakeRecordable() noexcept { - return std::unique_ptr(new sdktrace::SpanData); + return std::unique_ptr(new sdktrace::SpanData); } sdktrace::ExportResult OStreamSpanExporter::Export( const nostd::span> &spans) noexcept { - if (isShutdown_) - { - return sdktrace::ExportResult::kFailure; - } - - for (auto &recordable : spans) - { - auto span = std::unique_ptr( - static_cast(recordable.release())); + if(isShutdown_) + { + return sdktrace::ExportResult::kFailure; + } - if (span != nullptr) + for (auto &recordable : spans) { + auto span = std::unique_ptr( + static_cast(recordable.release())); + + if (span != nullptr) + { - char trace_id[32] = {0}; - char span_id[16] = {0}; - char parent_span_id[16] = {0}; + char trace_id[32] = {0}; + char span_id[16] = {0}; + char parent_span_id[16] = {0}; - span->GetTraceId().ToLowerBase16(trace_id); - span->GetSpanId().ToLowerBase16(span_id); - span->GetParentSpanId().ToLowerBase16(parent_span_id); + span->GetTraceId().ToLowerBase16(trace_id); + span->GetSpanId().ToLowerBase16(span_id); + span->GetParentSpanId().ToLowerBase16(parent_span_id); - sout_ << "{" - << "\n name : " << span->GetName() - << "\n trace_id : " << std::string(trace_id, 32) - << "\n span_id : " << std::string(span_id, 16) - << "\n parent_span_id: " << std::string(parent_span_id, 16) - << "\n start : " << span->GetStartTime().time_since_epoch().count() - << "\n duration : " << span->GetDuration().count() - << "\n description : " << span->GetDescription() - << "\n status : " << statusMap[int(span->GetStatus())] - << "\n attributes : "; - printAttributes(span->GetAttributes()); - sout_ << "\n}\n"; + sout_ << "{" + << "\n name : " << span->GetName() + << "\n trace_id : " << std::string(trace_id, 32) + << "\n span_id : " << std::string(span_id, 16) + << "\n parent_span_id: " << std::string(parent_span_id, 16) + << "\n start : " << span->GetStartTime().time_since_epoch().count() + << "\n duration : " << span->GetDuration().count() + << "\n description : " << span->GetDescription() + << "\n status : " << statusMap[int(span->GetStatus())] + << "\n attributes : "; + printAttributes(span->GetAttributes()); + sout_ << "\n}\n"; + } } - } - return sdktrace::ExportResult::kSuccess; + return sdktrace::ExportResult::kSuccess; } -void OStreamSpanExporter::Shutdown(std::chrono::microseconds timeout) noexcept +void OStreamSpanExporter::Shutdown(std::chrono::microseconds timeout) noexcept { isShutdown_ = true; } -} // namespace trace -} // namespace exporter +} // namespace trace +} // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/ostream/test/ostream_span_test.cc b/exporters/ostream/test/ostream_span_test.cc index e1f0c6b937..5bc0697b56 100644 --- a/exporters/ostream/test/ostream_span_test.cc +++ b/exporters/ostream/test/ostream_span_test.cc @@ -1,13 +1,14 @@ -#include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/sdk/trace/simple_processor.h" -#include "opentelemetry/sdk/trace/span_data.h" #include "opentelemetry/sdk/trace/tracer_provider.h" #include "opentelemetry/trace/provider.h" +#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/sdk/trace/recordable.h" #include "opentelemetry/sdk/trace/exporter.h" #include "opentelemetry/exporters/ostream/span_exporter.h" + #include #include @@ -19,8 +20,7 @@ namespace sdktrace = opentelemetry::sdk::trace; // Testing Shutdown functionality of OStreamSpanExporter, should expect no data to be sent to Stream TEST(OStreamSpanExporter, Shutdown) { - auto exporter = std::unique_ptr( - new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); @@ -41,20 +41,19 @@ TEST(OStreamSpanExporter, Shutdown) std::cout.rdbuf(sbuf); - ASSERT_EQ(stdoutOutput.str(), ""); + ASSERT_EQ(stdoutOutput.str(),""); } // Testing what a default span that is not changed will print out, either all 0's or empty values TEST(OStreamSpanExporter, PrintDefaultSpan) { - auto exporter = std::unique_ptr( - new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto recordable = processor->MakeRecordable(); - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -75,25 +74,24 @@ TEST(OStreamSpanExporter, PrintDefaultSpan) std::cout.rdbuf(sbuf); std::string expectedOutput = - "{\n" - " name : \n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : 0\n" - " duration : 0\n" - " description : \n" - " status : OK\n" - " attributes : \n" - "}\n"; - ASSERT_EQ(stdoutOutput.str(), expectedOutput); + "{\n" + " name : \n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : 0\n" + " duration : 0\n" + " description : \n" + " status : OK\n" + " attributes : \n" + "}\n"; + ASSERT_EQ(stdoutOutput.str(),expectedOutput); } // Testing if the changes we make to a span will carry over through the exporter TEST(OStreamSpanExporter, PrintChangedSpanCout) { - auto exporter = std::unique_ptr( - new opentelemetry::exporter::trace::OStreamSpanExporter); + auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); @@ -102,7 +100,7 @@ TEST(OStreamSpanExporter, PrintChangedSpanCout) recordable->SetName("Test Span"); opentelemetry::core::SystemTimestamp now(std::chrono::system_clock::now()); - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -111,7 +109,7 @@ TEST(OStreamSpanExporter, PrintChangedSpanCout) recordable->SetStartTime(now); recordable->SetDuration(std::chrono::nanoseconds(100)); - recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED, "Test Description"); + recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED,"Test Description"); recordable->SetAttribute("attr1", "string"); @@ -131,35 +129,32 @@ TEST(OStreamSpanExporter, PrintChangedSpanCout) std::string start = std::to_string(now.time_since_epoch().count()); std::string expectedOutput = - "{\n" - " name : Test Span\n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : " + - start + - "\n" - " duration : 100\n" - " description : Test Description\n" - " status : UNIMPLEMENTED\n" - " attributes : attr1: string\n" - "}\n"; - ASSERT_EQ(stdoutOutput.str(), expectedOutput); + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : " + start + "\n" + " duration : 100\n" + " description : Test Description\n" + " status : UNIMPLEMENTED\n" + " attributes : attr1: string\n" + "}\n"; + ASSERT_EQ(stdoutOutput.str(),expectedOutput); } // PrintChangedSpan to std::cerr TEST(OStreamSpanExporter, PrintChangedSpanCerr) { - auto exporter = std::unique_ptr( - new opentelemetry::exporter::trace::OStreamSpanExporter(std::cerr)); + auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter(std::cerr)); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto recordable = processor->MakeRecordable(); recordable->SetName("Test Span"); - - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -170,10 +165,10 @@ TEST(OStreamSpanExporter, PrintChangedSpanCerr) recordable->SetStartTime(now); recordable->SetDuration(std::chrono::nanoseconds(100)); - recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED, "Test Description"); + recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED,"Test Description"); std::array array2 = {false, true, false}; - opentelemetry::nostd::span span2{array2.data(), array2.size()}; + opentelemetry::nostd::span span2{array2.data(), array2.size()}; recordable->SetAttribute("attr1", span2); // Create stringstream to redirect to @@ -192,27 +187,24 @@ TEST(OStreamSpanExporter, PrintChangedSpanCerr) std::string start = std::to_string(now.time_since_epoch().count()); std::string expectedOutput = - "{\n" - " name : Test Span\n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : " + - start + - "\n" - " duration : 100\n" - " description : Test Description\n" - " status : UNIMPLEMENTED\n" - " attributes : attr1: [0,1,0]\n" - "}\n"; - ASSERT_EQ(stdcerrOutput.str(), expectedOutput); + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : " + start + "\n" + " duration : 100\n" + " description : Test Description\n" + " status : UNIMPLEMENTED\n" + " attributes : attr1: [0,1,0]\n" + "}\n"; + ASSERT_EQ(stdcerrOutput.str(),expectedOutput); } // PrintChangedSpan to std::clog TEST(OStreamSpanExporter, PrintChangedSpanClog) { - auto exporter = std::unique_ptr( - new opentelemetry::exporter::trace::OStreamSpanExporter(std::clog)); + auto exporter = std::unique_ptr(new opentelemetry::exporter::trace::OStreamSpanExporter(std::clog)); auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); @@ -220,7 +212,7 @@ TEST(OStreamSpanExporter, PrintChangedSpanClog) recordable->SetName("Test Span"); - constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t trace_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8,1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::TraceId t_id(trace_id_buf); constexpr uint8_t span_id_buf[] = {1, 2, 3, 4, 5, 6, 7, 8}; opentelemetry::trace::SpanId s_id(span_id_buf); @@ -230,10 +222,10 @@ TEST(OStreamSpanExporter, PrintChangedSpanClog) recordable->SetStartTime(now); recordable->SetDuration(std::chrono::nanoseconds(100)); - recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED, "Test Description"); + recordable->SetStatus(opentelemetry::trace::CanonicalCode::UNIMPLEMENTED,"Test Description"); std::array array1 = {1, 2, 3}; - opentelemetry::nostd::span span1{array1.data(), array1.size()}; + opentelemetry::nostd::span span1{array1.data(), array1.size()}; recordable->SetAttribute("attr1", span1); // Create stringstream to redirect to @@ -252,18 +244,16 @@ TEST(OStreamSpanExporter, PrintChangedSpanClog) std::string start = std::to_string(now.time_since_epoch().count()); std::string expectedOutput = - "{\n" - " name : Test Span\n" - " trace_id : 01020304050607080102030405060708\n" - " span_id : 0102030405060708\n" - " parent_span_id: 0102030405060708\n" - " start : " + - start + - "\n" - " duration : 100\n" - " description : Test Description\n" - " status : UNIMPLEMENTED\n" - " attributes : attr1: [1,2,3]\n" - "}\n"; - ASSERT_EQ(stdclogOutput.str(), expectedOutput); + "{\n" + " name : Test Span\n" + " trace_id : 01020304050607080102030405060708\n" + " span_id : 0102030405060708\n" + " parent_span_id: 0102030405060708\n" + " start : " + start + "\n" + " duration : 100\n" + " description : Test Description\n" + " status : UNIMPLEMENTED\n" + " attributes : attr1: [1,2,3]\n" + "}\n"; + ASSERT_EQ(stdclogOutput.str(),expectedOutput); } diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index a10357a460..fe15830e85 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -34,10 +34,10 @@ cc_library( cc_library( name = "otlp_exporter", srcs = [ - "src/otlp_exporter.cc", + 'src/otlp_exporter.cc', ], hdrs = [ - "include/opentelemetry/exporters/otlp/otlp_exporter.h", + 'include/opentelemetry/exporters/otlp/otlp_exporter.h', ], strip_include_prefix = "include", deps = [ @@ -60,7 +60,7 @@ cc_test( ) cc_test( - name = "otlp_exporter_test", + name = "otlp_exporter_test", srcs = ["test/otlp_exporter_test.cc"], deps = [ ":otlp_exporter", diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 91a3d89337..cd99350d21 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -5,8 +5,9 @@ target_link_libraries(opentelemetry_exporter_otprotocol $) add_executable(recordable_test test/recordable_test.cc) -target_link_libraries( - recordable_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_otprotocol protobuf::libprotobuf) -gtest_add_tests(TARGET recordable_test TEST_PREFIX exporter. TEST_LIST - recordable_test) +target_link_libraries(recordable_test + ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_otprotocol + protobuf::libprotobuf) +gtest_add_tests(TARGET recordable_test TEST_PREFIX exporter. TEST_LIST recordable_test) diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h index 16a5252f0b..4ac324f3ca 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_exporter.h @@ -1,7 +1,7 @@ #pragma once -#include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h" #include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace exporter @@ -31,15 +31,14 @@ class OtlpExporter final : public opentelemetry::sdk::trace::SpanExporter * @param spans a span of unique pointers to span recordables */ sdk::trace::ExportResult Export( - const nostd::span> &spans) noexcept override; + const nostd::span> &spans) noexcept override; /** * Shut down the exporter. * @param timeout an optional timeout, the default timeout of 0 means that no * timeout is applied. */ - void Shutdown( - std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override{}; + void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {}; private: // For testing @@ -49,10 +48,10 @@ class OtlpExporter final : public opentelemetry::sdk::trace::SpanExporter std::unique_ptr trace_service_stub_; /** - * Create an OtlpExporter using the specified service stub. - * Only tests can call this constructor directly. - * @param stub the service stub to be used for exporting - */ + * Create an OtlpExporter using the specified service stub. + * Only tests can call this constructor directly. + * @param stub the service stub to be used for exporting + */ OtlpExporter(std::unique_ptr stub); }; } // namespace otlp diff --git a/exporters/otlp/test/otlp_exporter_benchmark.cc b/exporters/otlp/test/otlp_exporter_benchmark.cc index 0accff0bf4..191c7ab6a1 100644 --- a/exporters/otlp/test/otlp_exporter_benchmark.cc +++ b/exporters/otlp/test/otlp_exporter_benchmark.cc @@ -15,10 +15,10 @@ const int kNumIterations = 1000; const trace::TraceId kTraceId(std::array( {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})); -const trace::SpanId kSpanId(std::array({0, 0, 0, 0, 0, 0, 0, - 2})); -const trace::SpanId kParentSpanId(std::array({0, 0, 0, 0, 0, 0, - 0, 3})); +const trace::SpanId kSpanId(std::array( + {0, 0, 0, 0, 0, 0, 0, 2})); +const trace::SpanId kParentSpanId(std::array( + {0, 0, 0, 0, 0, 0, 0, 3})); // ----------------------- Helper classes and functions ------------------------ @@ -120,7 +120,7 @@ void BM_OtlpExporterEmptySpans(benchmark::State &state) std::unique_ptr testpeer(new OtlpExporterTestPeer()); auto exporter = testpeer->GetExporter(); - while (state.KeepRunningBatch(kNumIterations)) + while(state.KeepRunningBatch(kNumIterations)) { std::array, kBatchSize> recordables; CreateEmptySpans(recordables); @@ -135,7 +135,7 @@ void BM_OtlpExporterSparseSpans(benchmark::State &state) std::unique_ptr testpeer(new OtlpExporterTestPeer()); auto exporter = testpeer->GetExporter(); - while (state.KeepRunningBatch(kNumIterations)) + while(state.KeepRunningBatch(kNumIterations)) { std::array, kBatchSize> recordables; CreateSparseSpans(recordables); @@ -150,7 +150,7 @@ void BM_OtlpExporterDenseSpans(benchmark::State &state) std::unique_ptr testpeer(new OtlpExporterTestPeer()); auto exporter = testpeer->GetExporter(); - while (state.KeepRunningBatch(kNumIterations)) + while(state.KeepRunningBatch(kNumIterations)) { std::array, kBatchSize> recordables; CreateDenseSpans(recordables); diff --git a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h index 66a4c81dfb..6e646765d1 100644 --- a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h +++ b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h @@ -8,9 +8,9 @@ #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/trace/recordable.h" -#include "opentelemetry/sdk/trace/span_data.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/span.h" +#include "opentelemetry/sdk/trace/span_data.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" @@ -20,23 +20,19 @@ using opentelemetry::sdk::trace::SpanDataEvent; namespace trace_api = opentelemetry::trace; OPENTELEMETRY_BEGIN_NAMESPACE -namespace ext -{ -namespace zpages -{ +namespace ext { +namespace zpages { /** * This class is a threadsafe version of span data used for zpages in OT */ -class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable -{ -public: +class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable { + public: /** * Get the trace id for this span * @return the trace id for this span */ - opentelemetry::trace::TraceId GetTraceId() const noexcept - { + opentelemetry::trace::TraceId GetTraceId() const noexcept { std::lock_guard lock(mutex_); return trace_id_; } @@ -45,8 +41,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the span id for this span * @return the span id for this span */ - opentelemetry::trace::SpanId GetSpanId() const noexcept - { + opentelemetry::trace::SpanId GetSpanId() const noexcept { std::lock_guard lock(mutex_); return span_id_; } @@ -55,8 +50,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the parent span id for this span * @return the span id for this span's parent */ - opentelemetry::trace::SpanId GetParentSpanId() const noexcept - { + opentelemetry::trace::SpanId GetParentSpanId() const noexcept { std::lock_guard lock(mutex_); return parent_span_id_; } @@ -65,8 +59,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the name for this span * @return the name for this span */ - opentelemetry::nostd::string_view GetName() const noexcept - { + opentelemetry::nostd::string_view GetName() const noexcept { std::lock_guard lock(mutex_); return name_; } @@ -75,8 +68,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the status for this span * @return the status for this span */ - opentelemetry::trace::CanonicalCode GetStatus() const noexcept - { + opentelemetry::trace::CanonicalCode GetStatus() const noexcept { std::lock_guard lock(mutex_); return status_code_; } @@ -85,8 +77,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the status description for this span * @return the description of the the status of this span */ - opentelemetry::nostd::string_view GetDescription() const noexcept - { + opentelemetry::nostd::string_view GetDescription() const noexcept { std::lock_guard lock(mutex_); return status_desc_; } @@ -95,8 +86,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the start time for this span * @return the start time for this span */ - opentelemetry::core::SystemTimestamp GetStartTime() const noexcept - { + opentelemetry::core::SystemTimestamp GetStartTime() const noexcept { std::lock_guard lock(mutex_); return start_time_; } @@ -105,8 +95,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the duration for this span * @return the duration for this span */ - std::chrono::nanoseconds GetDuration() const noexcept - { + std::chrono::nanoseconds GetDuration() const noexcept { std::lock_guard lock(mutex_); return duration_; } @@ -115,53 +104,50 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable * Get the attributes for this span * @return the attributes for this span */ - const std::unordered_map GetAttributes() const noexcept - { + const std::unordered_map GetAttributes() + const noexcept { std::lock_guard lock(mutex_); return attributes_; } void SetIds(opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, - opentelemetry::trace::SpanId parent_span_id) noexcept override - { + opentelemetry::trace::SpanId parent_span_id) noexcept override { std::lock_guard lock(mutex_); - trace_id_ = trace_id; - span_id_ = span_id; + trace_id_ = trace_id; + span_id_ = span_id; parent_span_id_ = parent_span_id; } - void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override - { + void SetAttribute(nostd::string_view key, + const common::AttributeValue &value) noexcept override { std::lock_guard lock(mutex_); attributes_[std::string(key)] = nostd::visit(converter_, value); } - void SetStatus(trace_api::CanonicalCode code, nostd::string_view description) noexcept override - { + void SetStatus(trace_api::CanonicalCode code, + nostd::string_view description) noexcept override { std::lock_guard lock(mutex_); status_code_ = code; status_desc_ = std::string(description); } - void SetName(nostd::string_view name) noexcept override - { + void SetName(nostd::string_view name) noexcept override { std::lock_guard lock(mutex_); name_ = std::string(name); } - void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override - { + void SetStartTime( + opentelemetry::core::SystemTimestamp start_time) noexcept override { std::lock_guard lock(mutex_); start_time_ = start_time; } - void SetDuration(std::chrono::nanoseconds duration) noexcept override - { + void SetDuration(std::chrono::nanoseconds duration) noexcept override { std::lock_guard lock(mutex_); duration_ = duration; } - + void AddLink( opentelemetry::trace::SpanContext span_context, const trace_api::KeyValueIterable &attributes = @@ -171,7 +157,7 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable (void)span_context; (void)attributes; } - + void AddEvent( nostd::string_view name, core::SystemTimestamp timestamp = core::SystemTimestamp(std::chrono::system_clock::now()), @@ -183,7 +169,25 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable // TODO: handle attributes } -private: + ThreadsafeSpanData(){} + ThreadsafeSpanData(const ThreadsafeSpanData &threadsafe_span_data) : ThreadsafeSpanData( + threadsafe_span_data, std::lock_guard(threadsafe_span_data.mutex_)) + {} + + private: + ThreadsafeSpanData(const ThreadsafeSpanData &threadsafe_span_data, const std::lock_guard &) + :trace_id_(threadsafe_span_data.trace_id_), + span_id_(threadsafe_span_data.span_id_), + parent_span_id_(threadsafe_span_data.parent_span_id_), + start_time_(threadsafe_span_data.start_time_), + duration_(threadsafe_span_data.duration_), + name_(threadsafe_span_data.name_), + status_code_(threadsafe_span_data.status_code_), + status_desc_(threadsafe_span_data.status_desc_), + attributes_(threadsafe_span_data.attributes_), + events_(threadsafe_span_data.events_), + converter_(threadsafe_span_data.converter_){} + mutable std::mutex mutex_; opentelemetry::trace::TraceId trace_id_; opentelemetry::trace::SpanId span_id_; @@ -191,7 +195,8 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable core::SystemTimestamp start_time_; std::chrono::nanoseconds duration_{0}; std::string name_; - opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; + opentelemetry::trace::CanonicalCode status_code_{ + opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; std::unordered_map attributes_; std::vector events_; diff --git a/ext/include/opentelemetry/ext/zpages/tracez_processor.h b/ext/include/opentelemetry/ext/zpages/tracez_processor.h index 926e430ead..ccc02cd5c7 100644 --- a/ext/include/opentelemetry/ext/zpages/tracez_processor.h +++ b/ext/include/opentelemetry/ext/zpages/tracez_processor.h @@ -4,12 +4,12 @@ #include #include #include -#include #include +#include #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/recordable.h" -#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/ext/zpages/threadsafe_span_data.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace ext @@ -20,13 +20,12 @@ namespace zpages * The span processor passes and stores running and completed recordables (casted as span_data) * to be used by the TraceZ Data Aggregator. */ -class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor -{ -public: - struct CollectedSpans - { - std::unordered_set running; - std::vector> completed; +class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor { + public: + + struct CollectedSpans { + std::unordered_set running; + std::vector> completed; }; /* @@ -40,13 +39,11 @@ class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor */ std::unique_ptr MakeRecordable() noexcept override { - return std::unique_ptr( - new opentelemetry::sdk::trace::SpanData); + return std::unique_ptr(new opentelemetry::ext::zpages::ThreadsafeSpanData); } /* - * OnStart is called when a span starts; the recordable is cast to span_data and added to - * running_spans. + * OnStart is called when a span starts; the recordable is cast to span_data and added to running_spans. * @param span a recordable for a span that was just started */ void OnStart(opentelemetry::sdk::trace::Recordable &span) noexcept override; @@ -76,8 +73,7 @@ class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor * timeout is applied. Currently, timeout does nothing. */ void ForceFlush( - std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override - {} + std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {} /* * Shut down the processor and do any cleanup required, which is none. @@ -86,10 +82,9 @@ class TracezSpanProcessor : public opentelemetry::sdk::trace::SpanProcessor * @param timeout an optional timeout, the default timeout of 0 means that no * timeout is applied. Currently, timeout does nothing. */ - void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override - {} + void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {} -private: + private: mutable std::mutex mtx_; CollectedSpans spans_; }; diff --git a/ext/src/zpages/BUILD b/ext/src/zpages/BUILD index a59d525897..d67768ddb7 100644 --- a/ext/src/zpages/BUILD +++ b/ext/src/zpages/BUILD @@ -21,7 +21,9 @@ cc_library( include_prefix = "ext/zpages", deps = [ "//api", - "//ext:headers", "//sdk:headers", + "//ext:headers", + "@github_nlohmann_json//:json", ], ) + diff --git a/ext/src/zpages/CMakeLists.txt b/ext/src/zpages/CMakeLists.txt index eeef261fba..8b60d36584 100644 --- a/ext/src/zpages/CMakeLists.txt +++ b/ext/src/zpages/CMakeLists.txt @@ -1,8 +1,11 @@ add_library( opentelemetry_zpages - tracez_processor.cc ../../include/opentelemetry/ext/zpages/tracez_processor.h) + tracez_processor.cc tracez_data_aggregator.cc + ../../include/opentelemetry/ext/zpages/tracez_processor.h + ../../include/opentelemetry/ext/zpages/tracez_data_aggregator.h) target_include_directories(opentelemetry_zpages PUBLIC ../../include) target_link_libraries(opentelemetry_zpages opentelemetry_api opentelemetry_trace) + diff --git a/ext/src/zpages/tracez_processor.cc b/ext/src/zpages/tracez_processor.cc index 8e1dc5600d..70c8ad7014 100644 --- a/ext/src/zpages/tracez_processor.cc +++ b/ext/src/zpages/tracez_processor.cc @@ -1,42 +1,37 @@ #include "opentelemetry/ext/zpages/tracez_processor.h" OPENTELEMETRY_BEGIN_NAMESPACE -namespace ext -{ -namespace zpages -{ +namespace ext { +namespace zpages { + + void TracezSpanProcessor::OnStart(opentelemetry::sdk::trace::Recordable &span) noexcept { + std::lock_guard lock(mtx_); + spans_.running.insert(static_cast(&span)); + } + + void TracezSpanProcessor::OnEnd(std::unique_ptr &&span) noexcept { + if (span == nullptr) return; + auto span_raw = static_cast(span.get()); + std::lock_guard lock(mtx_); + auto span_it = spans_.running.find(span_raw); + if (span_it != spans_.running.end()) { + spans_.running.erase(span_it); + spans_.completed.push_back( + std::unique_ptr( + static_cast(span.release()))); + } + } -void TracezSpanProcessor::OnStart(opentelemetry::sdk::trace::Recordable &span) noexcept -{ - std::lock_guard lock(mtx_); - spans_.running.insert(static_cast(&span)); -} -void TracezSpanProcessor::OnEnd( - std::unique_ptr &&span) noexcept -{ - if (span == nullptr) - return; - auto span_raw = static_cast(span.get()); - std::lock_guard lock(mtx_); - auto span_it = spans_.running.find(span_raw); - if (span_it != spans_.running.end()) - { - spans_.running.erase(span_it); - spans_.completed.push_back(std::unique_ptr( - static_cast(span.release()))); + TracezSpanProcessor::CollectedSpans TracezSpanProcessor::GetSpanSnapshot() noexcept { + CollectedSpans snapshot; + std::lock_guard lock(mtx_); + snapshot.running = spans_.running; + snapshot.completed = std::move(spans_.completed); + spans_.completed.clear(); + return snapshot; } -} -TracezSpanProcessor::CollectedSpans TracezSpanProcessor::GetSpanSnapshot() noexcept -{ - CollectedSpans snapshot; - std::lock_guard lock(mtx_); - snapshot.running = spans_.running; - snapshot.completed = std::move(spans_.completed); - spans_.completed.clear(); - return snapshot; -} } // namespace zpages } // namespace ext diff --git a/ext/test/zpages/BUILD b/ext/test/zpages/BUILD index 35853ab51e..c1dcb3bca0 100644 --- a/ext/test/zpages/BUILD +++ b/ext/test/zpages/BUILD @@ -4,8 +4,8 @@ cc_test( "threadsafe_span_data_test.cc", ], deps = [ - "//ext/src/zpages", "//sdk/src/trace", + "//ext/src/zpages", "@com_google_googletest//:gtest_main", ], ) @@ -28,8 +28,8 @@ cc_test( "tracez_processor_test.cc", ], deps = [ - "//ext/src/zpages", "//sdk/src/trace", + "//ext/src/zpages", "@com_google_googletest//:gtest_main", ], ) diff --git a/ext/test/zpages/CMakeLists.txt b/ext/test/zpages/CMakeLists.txt index 6f45e656d3..38e5cedeb2 100644 --- a/ext/test/zpages/CMakeLists.txt +++ b/ext/test/zpages/CMakeLists.txt @@ -1,7 +1,11 @@ -foreach(testname tracez_processor_test threadsafe_span_data_test) +foreach(testname tracez_processor_test tracez_data_aggregator_test threadsafe_span_data_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_zpages) - gtest_add_tests(TARGET ${testname} TEST_PREFIX ext. TEST_LIST ${testname}) + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX ext. + TEST_LIST ${testname}) endforeach() + diff --git a/ext/test/zpages/threadsafe_span_data_test.cc b/ext/test/zpages/threadsafe_span_data_test.cc index 4b0b6ce42a..51f6765eb0 100644 --- a/ext/test/zpages/threadsafe_span_data_test.cc +++ b/ext/test/zpages/threadsafe_span_data_test.cc @@ -6,9 +6,9 @@ #include #include -using opentelemetry::ext::zpages::ThreadsafeSpanData; using opentelemetry::sdk::trace::AttributeConverter; using opentelemetry::sdk::trace::SpanDataAttributeValue; +using opentelemetry::ext::zpages::ThreadsafeSpanData; TEST(ThreadsafeSpanData, DefaultValues) { diff --git a/ext/test/zpages/tracez_processor_test.cc b/ext/test/zpages/tracez_processor_test.cc index 42a8736302..29a77de3e7 100644 --- a/ext/test/zpages/tracez_processor_test.cc +++ b/ext/test/zpages/tracez_processor_test.cc @@ -17,26 +17,23 @@ using namespace opentelemetry::ext::zpages; * Helper function uses the current processor to update spans contained in completed_spans * and running_spans. completed_spans contains all spans (cumulative), unless marked otherwise */ -void UpdateSpans(std::shared_ptr &processor, - std::vector> &completed, - std::unordered_set &running, - bool store_only_new_completed = false) -{ +void UpdateSpans(std::shared_ptr& processor, + std::vector>& completed, + std::unordered_set& running, + bool store_only_new_completed = false) { auto spans = processor->GetSpanSnapshot(); - running = spans.running; - if (store_only_new_completed) - { + running = spans.running; + if (store_only_new_completed) { completed.clear(); completed = std::move(spans.completed); - } - else - { + } else { std::move(spans.completed.begin(), spans.completed.end(), - std::inserter(completed, completed.end())); + std::inserter(completed, completed.end())); } spans.completed.clear(); } + /* * Returns true if all the span names in the name vector within the given range appears in * at least the same frequency as they do in running_spans. @@ -46,45 +43,37 @@ void UpdateSpans(std::shared_ptr &processor, * If 1-1 correspondance marked, return true if completed has all names in same frequency, * no more or less */ -bool ContainsNames(const std::vector &names, - std::unordered_set &running, - unsigned int name_start = 0, - unsigned int name_end = 0, - bool one_to_one_correspondence = false) -{ - if (name_end == 0) - name_end = names.size(); +bool ContainsNames(const std::vector& names, + std::unordered_set& running, + unsigned int name_start = 0, unsigned int name_end = 0, + bool one_to_one_correspondence = false) { + if (name_end == 0) name_end = names.size(); unsigned int num_names = name_end - name_start; - if (num_names > running.size() || // More names than spans, can't have all names - (one_to_one_correspondence && num_names != running.size())) - { + if (num_names > running.size() || // More names than spans, can't have all names + (one_to_one_correspondence && num_names != running.size())) { return false; } std::vector is_contained(num_names, false); // Mark all names that are contained only once // in the order they appear - for (auto &span : running) - { - for (unsigned int i = 0; i < num_names; i++) - { - if (span->GetName() == names[name_start + i] && !is_contained[i]) - { + for (auto &span : running) { + for (unsigned int i = 0; i < num_names; i++) { + if (span->GetName() == names[name_start + i] && !is_contained[i]) { is_contained[i] = true; break; } } } - for (auto &&b : is_contained) - if (!b) - return false; + for (auto &&b : is_contained) if (!b) return false; return true; } + /* * Returns true if all the span names in the nam vector within the given range appears in * at least the same frequency as they do in completed_spans @@ -94,126 +83,114 @@ bool ContainsNames(const std::vector &names, * If 1-1 correspondance marked, return true if completed has all names in same frequency, * no more or less */ -bool ContainsNames(const std::vector &names, - std::vector> &completed, - unsigned int name_start = 0, - unsigned int name_end = 0, - bool one_to_one_correspondence = false) -{ +bool ContainsNames(const std::vector& names, + std::vector>& completed, + unsigned int name_start = 0, unsigned int name_end = 0, + bool one_to_one_correspondence = false) { - if (name_end == 0) - name_end = names.size(); + if (name_end == 0) name_end = names.size(); unsigned int num_names = name_end - name_start; - if (num_names > completed.size() || (one_to_one_correspondence && num_names != completed.size())) - { - return false; + if (num_names > completed.size() || + (one_to_one_correspondence && num_names != completed.size())) { + return false; } std::vector is_contained(num_names, false); - for (auto &span : completed) - { - for (unsigned int i = 0; i < num_names; i++) - { - if (span->GetName() == names[name_start + i] && !is_contained[i]) - { + for (auto &span : completed) { + for (unsigned int i = 0; i < num_names; i++) { + if (span->GetName() == names[name_start + i] && !is_contained[i]) { is_contained[i] = true; break; } } } - for (auto &&b : is_contained) - if (!b) - return false; + for (auto &&b : is_contained) if (!b) return false; return true; } + /* * Helper function calls GetSpanSnapshot() i times and does nothing with it * otherwise. Used for testing thread safety */ -void GetManySnapshots(std::shared_ptr &processor, int i) -{ - for (; i > 0; i--) - processor->GetSpanSnapshot(); +void GetManySnapshots(std::shared_ptr& processor, int i) { + for (; i > 0; i--) processor->GetSpanSnapshot(); } + /* * Helper function that creates i spans, which are added into the passed * in vector. Used for testing thread safety */ -void StartManySpans( - std::vector> &spans, - std::shared_ptr tracer, - int i) -{ - for (; i > 0; i--) - spans.push_back(tracer->StartSpan("span")); +void StartManySpans(std::vector> &spans, + std::shared_ptr tracer, int i) { + for (; i > 0; i--) spans.push_back(tracer->StartSpan("span")); } + /* * Helper function that ends all spans in the passed in span vector. Used * for testing thread safety */ -void EndAllSpans(std::vector> &spans) -{ - for (auto &span : spans) - span->End(); +void EndAllSpans(std::vector> &spans) { + for (auto &span : spans) span->End(); } + //////////////////////////////// TEST FIXTURE ////////////////////////////////////// /* * Reduce code duplication by having single area with shared setup code */ -class TracezProcessor : public ::testing::Test -{ -protected: - void SetUp() override - { - processor = std::shared_ptr(new TracezSpanProcessor()); - tracer = std::shared_ptr(new Tracer(processor)); +class TracezProcessor : public ::testing::Test { + protected: + void SetUp() override { + processor = std::shared_ptr(new TracezSpanProcessor()); + tracer = std::shared_ptr(new Tracer(processor)); auto spans = processor->GetSpanSnapshot(); - running = spans.running; - completed = std::move(spans.completed); + running = spans.running; + completed = std::move(spans.completed); span_names = {"s0", "s2", "s1", "s1", "s"}; + } std::shared_ptr processor; std::shared_ptr tracer; - std::unordered_set running; - std::vector> completed; + std::unordered_set running; + std::vector> completed; std::vector span_names; std::vector> span_vars; + }; + ///////////////////////////////////////// TESTS /////////////////////////////////// /* * Test if both span containers are empty when no spans exist or are added. * Ensures no rogue spans appear in the containers somehow. */ -TEST_F(TracezProcessor, NoSpans) -{ +TEST_F(TracezProcessor, NoSpans) { auto recordable = processor->MakeRecordable(); EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 0); } + /* * Test if a single span moves from running to completed at expected times. * All completed spans are stored. Ensures basic functionality and that accumulation * can happen - */ -TEST_F(TracezProcessor, OneSpanCumulative) -{ +*/ +TEST_F(TracezProcessor, OneSpanCumulative) { auto span = tracer->StartSpan(span_names[0]); UpdateSpans(processor, completed, running); @@ -229,49 +206,46 @@ TEST_F(TracezProcessor, OneSpanCumulative) EXPECT_EQ(completed.size(), 1); } + /* * Test if multiple spans move from running to completed at expected times. Check if * all are in a container, either running/completed during checks. Ensures basic functionality * and that accumulation can happen for many spans * All completed spans are stored. - */ -TEST_F(TracezProcessor, MultipleSpansCumulative) -{ +*/ +TEST_F(TracezProcessor, MultipleSpansCumulative) { EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 0); // Start and store spans using span_names - for (const auto &name : span_names) - span_vars.push_back(tracer->StartSpan(name)); + for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), span_names.size()); EXPECT_EQ(completed.size(), 0); // End all spans - for (auto &span : span_vars) - span->End(); + for (auto &span : span_vars) span->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), span_names.size()); } + /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Middle spans end first. Ensures basic functionality * and that accumulation can happen for many spans even spans that start and end non- * sequentially. All completed spans are stored. - */ -TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) -{ - for (const auto &name : span_names) - span_vars.push_back(tracer->StartSpan(name)); +*/ +TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) { + for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, running)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), span_names.size()); EXPECT_EQ(completed.size(), 0); @@ -279,9 +253,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) span_vars[3]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -289,11 +263,11 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) span_vars[1]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, running, 2, 3)); // + s1 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 2)); // s2 - EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 2, 3)); // + s1 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 2)); // s2 + EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4)); // s1 EXPECT_EQ(running.size(), 3); EXPECT_EQ(completed.size(), 2); @@ -301,9 +275,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) span_vars[2]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4)); // s2 s1 s1 EXPECT_EQ(running.size(), 2); EXPECT_EQ(completed.size(), 3); @@ -312,28 +286,27 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitCumulative) span_vars[4]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 5); } + /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Ensures basic functionality and that * accumulation can happen for many spans even spans that start and end non- * sequentially. All completed spans are stored. - */ -TEST_F(TracezProcessor, MultipleSpansOuterSplitCumulative) -{ - for (const auto &name : span_names) - span_vars.push_back(tracer->StartSpan(name)); +*/ +TEST_F(TracezProcessor, MultipleSpansOuterSplitCumulative) { + for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); // End last span span_vars[4]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 4)); // s0 s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s + EXPECT_TRUE(ContainsNames(span_names, running, 0, 4)); // s0 s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -341,29 +314,28 @@ TEST_F(TracezProcessor, MultipleSpansOuterSplitCumulative) span_vars[0]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 1, 4)); // s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s + EXPECT_TRUE(ContainsNames(span_names, running, 1, 4)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s EXPECT_EQ(running.size(), 3); EXPECT_EQ(completed.size(), 2); // End remaining Spans - for (int i = 1; i < 4; i++) - span_vars[i]->End(); + for (int i = 1; i < 4; i++) span_vars[i]->End(); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, completed)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 5); } + /* * Test if a single span moves from running to completed at expected times. * Ensure correct behavior even when spans are discarded. Only new completed * spans are stored. - */ -TEST_F(TracezProcessor, OneSpanNewOnly) -{ +*/ +TEST_F(TracezProcessor, OneSpanNewOnly) { auto span = tracer->StartSpan(span_names[0]); UpdateSpans(processor, completed, running, true); @@ -384,19 +356,18 @@ TEST_F(TracezProcessor, OneSpanNewOnly) EXPECT_EQ(completed.size(), 0); } + /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Middle spans end first. Ensure correct * behavior even when multiple spans are discarded, even when span starting and * ending is non-sequential. Only new completed spans are stored. */ -TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) -{ - for (const auto &name : span_names) - span_vars.push_back(tracer->StartSpan(name)); +TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) { + for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); UpdateSpans(processor, completed, running); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 5, true)); // s0 s2 s1 s1 s + EXPECT_TRUE(ContainsNames(span_names, running, 0, 5, true)); // s0 s2 s1 s1 s EXPECT_EQ(running.size(), span_names.size()); EXPECT_EQ(completed.size(), 0); @@ -404,9 +375,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) span_vars[3]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4, true)); // s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 3)); // s0 s2 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 3, 4, true)); // s1 EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -415,9 +386,9 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) span_vars[2]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 3, true)); // s2 s1 + EXPECT_TRUE(ContainsNames(span_names, running, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 4)); // + s + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 3, true)); // s2 s1 EXPECT_EQ(running.size(), 2); EXPECT_EQ(completed.size(), 2); @@ -426,8 +397,8 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) span_vars[4]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 - EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s + EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1)); // s0 + EXPECT_TRUE(ContainsNames(span_names, completed, 4)); // s EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 2); @@ -437,23 +408,22 @@ TEST_F(TracezProcessor, MultipleSpansMiddleSplitNewOnly) EXPECT_EQ(completed.size(), 0); } + /* * Test if multiple spans move from running to completed at expected times, * running/completed spans are split. Ensure correct behavior even when * multiple spans are discarded, even when span starting and ending is * non-sequential. Only new completed spans are stored. - */ -TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) -{ - for (const auto &name : span_names) - span_vars.push_back(tracer->StartSpan(name)); +*/ +TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) { + for (const auto &name : span_names) span_vars.push_back(tracer->StartSpan(name)); // End last span span_vars[4]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 0, 4, true)); // s0 s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 4, 5, true)); // s + EXPECT_TRUE(ContainsNames(span_names, running, 0, 4, true)); // s0 s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 4, 5, true)); // s EXPECT_EQ(running.size(), 4); EXPECT_EQ(completed.size(), 1); @@ -461,17 +431,16 @@ TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) span_vars[0]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, running, 1, 4, true)); // s2 s1 s1 - EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1, true)); // s0 + EXPECT_TRUE(ContainsNames(span_names, running, 1, 4, true)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 0, 1, true)); // s0 EXPECT_EQ(running.size(), 3); EXPECT_EQ(completed.size(), 1); // End remaining middle spans - for (int i = 1; i < 4; i++) - span_vars[i]->End(); + for (int i = 1; i < 4; i++) span_vars[i]->End(); UpdateSpans(processor, completed, running, true); - EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4, true)); // s2 s1 s1 + EXPECT_TRUE(ContainsNames(span_names, completed, 1, 4, true)); // s2 s1 s1 EXPECT_EQ(running.size(), 0); EXPECT_EQ(completed.size(), 3); @@ -481,12 +450,12 @@ TEST_F(TracezProcessor, MultipleSpansOuterSplitNewOnly) EXPECT_EQ(completed.size(), 0); } + /* * Test for ForceFlush and Shutdown code coverage, which do nothing. */ -TEST_F(TracezProcessor, FlushShutdown) -{ - auto pre_running_sz = running.size(); +TEST_F(TracezProcessor, FlushShutdown) { + auto pre_running_sz = running.size(); auto pre_completed_sz = completed.size(); processor->ForceFlush(); @@ -498,11 +467,11 @@ TEST_F(TracezProcessor, FlushShutdown) EXPECT_EQ(pre_completed_sz, completed.size()); } + /* * Test for thread safety when many spans start at the same time. */ -TEST_F(TracezProcessor, RunningThreadSafety) -{ +TEST_F(TracezProcessor, RunningThreadSafety) { std::vector> spans1; std::vector> spans2; @@ -513,11 +482,11 @@ TEST_F(TracezProcessor, RunningThreadSafety) start2.join(); } + /* * Test for thread safety when many spans end at the same time */ -TEST_F(TracezProcessor, CompletedThreadSafety) -{ +TEST_F(TracezProcessor, CompletedThreadSafety) { std::vector> spans1; std::vector> spans2; StartManySpans(spans1, tracer, 500); @@ -530,11 +499,11 @@ TEST_F(TracezProcessor, CompletedThreadSafety) end2.join(); } + /* * Test for thread safety when many snapshots are grabbed at the same time. */ -TEST_F(TracezProcessor, SnapshotThreadSafety) -{ +TEST_F(TracezProcessor, SnapshotThreadSafety) { std::vector> spans; std::thread snap1(GetManySnapshots, std::ref(processor), 500); @@ -552,11 +521,11 @@ TEST_F(TracezProcessor, SnapshotThreadSafety) snap4.join(); } + /* * Test for thread safety when many spans start while others are ending. */ -TEST_F(TracezProcessor, RunningCompletedThreadSafety) -{ +TEST_F(TracezProcessor, RunningCompletedThreadSafety) { std::vector> spans1; std::vector> spans2; StartManySpans(spans1, tracer, 500); @@ -568,11 +537,11 @@ TEST_F(TracezProcessor, RunningCompletedThreadSafety) end.join(); } + /* * Test for thread safety when many span start while snapshots are being grabbed. */ -TEST_F(TracezProcessor, RunningSnapshotThreadSafety) -{ +TEST_F(TracezProcessor, RunningSnapshotThreadSafety) { std::vector> spans; std::thread start(StartManySpans, std::ref(spans), tracer, 500); @@ -582,11 +551,11 @@ TEST_F(TracezProcessor, RunningSnapshotThreadSafety) snapshots.join(); } + /* * Test for thread safety when many spans end while snapshots are being grabbed. */ -TEST_F(TracezProcessor, SnapshotCompletedThreadSafety) -{ +TEST_F(TracezProcessor, SnapshotCompletedThreadSafety) { std::vector> spans; StartManySpans(spans, tracer, 500); @@ -597,11 +566,11 @@ TEST_F(TracezProcessor, SnapshotCompletedThreadSafety) end.join(); } + /* * Test for thread safety when many spans start and end while snapshots are being grabbed. */ -TEST_F(TracezProcessor, RunningSnapshotCompletedThreadSafety) -{ +TEST_F(TracezProcessor, RunningSnapshotCompletedThreadSafety) { std::vector> spans1; std::vector> spans2; StartManySpans(spans1, tracer, 500); @@ -614,3 +583,4 @@ TEST_F(TracezProcessor, RunningSnapshotCompletedThreadSafety) snapshots.join(); end.join(); } + diff --git a/sdk/include/opentelemetry/sdk/metrics/TBD b/sdk/include/opentelemetry/sdk/metrics/TBD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h deleted file mode 100644 index b997514208..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once - -#include -#include -#include "opentelemetry/core/timestamp.h" -#include "opentelemetry/metrics/instrument.h" -#include "opentelemetry/version.h" - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ - -enum class AggregatorKind -{ - Counter = 0, - MinMaxSumCount = 1, - Gauge = 2, - Sketch = 3, - Histogram = 4, - Exact = 5, -}; - -/* - * Performs calculations necessary to combine updates from instruments into an - * insightful value. - * Also stores current instrument values and checkpoints collected at intervals - * governing the entire pipeline. - */ -template -class Aggregator -{ -public: - Aggregator() = default; - - virtual ~Aggregator() = default; - - /** - * Receives a captured value from the instrument and applies it to the current aggregator value. - * - * @param val, the raw value used in aggregation - * @return none - */ - virtual void update(T val) = 0; - - /** - * Checkpoints the current value. This function will overwrite the current checkpoint with the - * current value. - * - * @param none - * @return none - */ - virtual void checkpoint() = 0; - - /** - * Merges the values of two aggregators in a semantically accurate manner. - * Merging will occur differently for different aggregators depending on the - * way values are tracked. - * - * @param other, the aggregator with merge with - * @return none - */ - void merge(Aggregator *other); - - /** - * Returns the checkpointed value - * - * @param none - * @return the value of the checkpoint - */ - virtual std::vector get_checkpoint() = 0; - - /** - * Returns the current value - * - * @param none - * @return the present aggregator value - */ - virtual std::vector get_values() = 0; - - /** - * Returns the instrument kind which this aggregator is associated with - * - * @param none - * @return the InstrumentKind of the aggregator's owner - */ - virtual opentelemetry::metrics::InstrumentKind get_instrument_kind() final { return kind_; } - - /** - * Returns the type of this aggregator - * - * @param none - * @return the AggregatorKind of this instrument - */ - virtual AggregatorKind get_aggregator_kind() final { return agg_kind_; } - - // virtual function to be overriden for the Histogram Aggregator - virtual std::vector get_boundaries() { return std::vector(); } - - // virtual function to be overriden for the Histogram Aggregator - virtual std::vector get_counts() { return std::vector(); } - - // virtual function to be overriden for Exact and Sketch Aggregators - virtual bool get_quant_estimation() { return false; } - - // virtual function to be overriden for Exact and Sketch Aggregators - virtual T get_quantiles(double q) { return values_[0]; } - - // virtual function to be overriden for Sketch Aggregator - virtual double get_error_bound() { return 0; } - - // virtual function to be overriden for Sketch Aggregator - virtual size_t get_max_buckets() { return 0; } - - // virtual function to be overriden for Gauge Aggregator - virtual core::SystemTimestamp get_checkpoint_timestamp() { return core::SystemTimestamp(); } - - // Custom copy constructor to handle the mutex - Aggregator(const Aggregator &cp) - { - values_ = cp.values_; - checkpoint_ = cp.checkpoint_; - kind_ = cp.kind_; - agg_kind_ = cp.agg_kind_; - // use default initialized mutex as they cannot be copied - } - -protected: - std::vector values_; - std::vector checkpoint_; - opentelemetry::metrics::InstrumentKind kind_; - std::mutex mu_; - AggregatorKind agg_kind_; -}; - -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h deleted file mode 100644 index 0bf44f6421..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include -#include -#include "opentelemetry/metrics/instrument.h" -#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" -#include "opentelemetry/version.h" - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ - -template -class CounterAggregator final : public Aggregator -{ - -public: - CounterAggregator(metrics_api::InstrumentKind kind) - { - this->kind_ = kind; - this->values_ = std::vector(1, 0); - this->checkpoint_ = std::vector(1, 0); - this->agg_kind_ = AggregatorKind::Counter; - } - - /** - * Recieves a captured value from the instrument and applies it to the current aggregator value. - * - * @param val, the raw value used in aggregation - * @return none - */ - void update(T val) override - { - this->mu_.lock(); - this->values_[0] += val; // atomic operation - this->mu_.unlock(); - } - - /** - * Checkpoints the current value. This function will overwrite the current checkpoint with the - * current value. - * - * @param none - * @return none - */ - void checkpoint() override - { - this->checkpoint_ = this->values_; - this->values_[0] = 0; - } - - /** - * Merges the values of two aggregators in a semantically accurate manner. - * In this case, merging only requires the the current values of the two aggregators be summed. - * - * @param other, the aggregator with merge with - * @return none - */ - void merge(CounterAggregator other) - { - if (this->agg_kind_ == other.agg_kind_) - { - this->mu_.lock(); - this->values_[0] += other.values_[0]; - this->checkpoint_[0] += other.checkpoint_[0]; - this->mu_.unlock(); - } - else - { -#if __EXCEPTIONS - throw std::invalid_argument("Aggregators of different types cannot be merged."); -#else - std::terminate(); -#endif - } - } - - /** - * Returns the checkpointed value - * - * @param none - * @return the value of the checkpoint - */ - virtual std::vector get_checkpoint() override { return this->checkpoint_; } - - /** - * Returns the current values - * - * @param none - * @return the present aggregator values - */ - virtual std::vector get_values() override { return this->values_; } -}; - -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h deleted file mode 100644 index 00ec1ae12d..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/exact_aggregator.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once - -#include "opentelemetry/metrics/instrument.h" -#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" -#include "opentelemetry/version.h" - -#include -#include -#include -#include - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ -/** - * This aggregator has two modes. In-order and quantile estimation. - * - * The first mode simply stores all values sent to the Update() - * function in a vector and maintains the order they were sent in. - * - * The second mode also stores all values sent to the Update() - * function in a vector but sorts this vector when Checkpoint() - * is called. This mode also includes a function, Quantile(), - * that estimates the quantiles of the recorded data. - * - * @tparam T the type of values stored in this aggregator. - */ -template -class ExactAggregator : public Aggregator -{ -public: - ExactAggregator(metrics_api::InstrumentKind kind, bool quant_estimation = false) - { - static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - this->kind_ = kind; - this->checkpoint_ = this->values_; - this->agg_kind_ = AggregatorKind::Exact; - quant_estimation_ = quant_estimation; - } - - ~ExactAggregator() = default; - - ExactAggregator(const ExactAggregator &cp) - { - this->values_ = cp.values_; - this->checkpoint_ = cp.checkpoint_; - this->kind_ = cp.kind_; - this->agg_kind_ = cp.agg_kind_; - quant_estimation_ = cp.quant_estimation_; - // use default initialized mutex as they cannot be copied - } - - /** - * Receives a captured value from the instrument and adds it to the values_ vector. - * - * @param val, the raw value used in aggregation - */ - void update(T val) override - { - this->mu_.lock(); - this->values_.push_back(val); - this->mu_.unlock(); - } - - /** - * Checkpoints the current values. This function will overwrite the current checkpoint with the - * current value. Sorts the values_ vector if quant_estimation_ == true - * - */ - void checkpoint() override - { - this->mu_.lock(); - if (quant_estimation_) - { - std::sort(this->values_.begin(), this->values_.end()); - } - this->checkpoint_ = this->values_; - this->values_.clear(); - this->mu_.unlock(); - } - - /** - * Merges two exact aggregators' values_ vectors together. - * - * @param other the aggregator to merge with this aggregator - */ - void merge(const ExactAggregator &other) - { - if (this->kind_ == other.kind_) - { - this->mu_.lock(); - // First merge values - this->values_.insert(this->values_.end(), other.values_.begin(), other.values_.end()); - // Now merge checkpoints - this->checkpoint_.insert(this->checkpoint_.end(), other.checkpoint_.begin(), - other.checkpoint_.end()); - this->mu_.unlock(); - } - else - { - // Log error - return; - } - } - - /** - * Performs quantile estimation on the checkpoint vector in this aggregator. - * This function only works if quant_estimation_ == true. - * @param q the quantile to estimate. 0 <= q <= 1 - * @return the nearest value in the vector to the exact quantile. - */ - T get_quantiles(double q) override - { - if (!quant_estimation_) - { -// Log error -#if __EXCEPTIONS - throw std::domain_error("Exact aggregator is not in quantile estimation mode!"); -#else - std::terminate(); -#endif - } - if (this->checkpoint_.size() == 0 || q < 0 || q > 1) - { -// Log error -#if __EXCEPTIONS - throw std::invalid_argument("Arg 'q' must be between 0 and 1, inclusive"); -#else - std::terminate(); -#endif - } - else if (q == 0 || this->checkpoint_.size() == 1) - { - return this->checkpoint_[0]; - } - else if (q == 1) - { - return this->checkpoint_[this->checkpoint_.size() - 1]; - } - else - { - float position = float(this->checkpoint_.size() - 1) * q; - int ceiling = ceil(position); - return this->checkpoint_[ceiling]; - } - } - - //////////////////////////ACCESSOR FUNCTIONS////////////////////////// - std::vector get_checkpoint() override { return this->checkpoint_; } - - std::vector get_values() override { return this->values_; } - - bool get_quant_estimation() override { return quant_estimation_; } - -private: - bool quant_estimation_; // Used to switch between in-order and quantile estimation modes -}; -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h deleted file mode 100644 index 7925f5e205..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once - -#include "opentelemetry/core/timestamp.h" -#include "opentelemetry/metrics/instrument.h" -#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" -#include "opentelemetry/version.h" - -#include -#include -#include - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ -/** - * This aggregator stores and maintains a vector of - * type T where the contents of the vector simply - * include the last value recorded to the aggregator. - * The aggregator also maintains a timestamp of when - * the last value was recorded. - * - * @tparam T the type of values stored in this aggregator. - */ -template -class GaugeAggregator : public Aggregator -{ -public: - explicit GaugeAggregator(metrics_api::InstrumentKind kind) - { - static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - this->kind_ = kind; - this->values_ = std::vector(1, 0); - this->checkpoint_ = this->values_; - this->agg_kind_ = AggregatorKind::Gauge; - current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); - } - - ~GaugeAggregator() = default; - - GaugeAggregator(const GaugeAggregator &cp) - { - this->values_ = cp.values_; - this->checkpoint_ = cp.checkpoint_; - this->kind_ = cp.kind_; - this->agg_kind_ = cp.agg_kind_; - current_timestamp_ = cp.current_timestamp_; - // use default initialized mutex as they cannot be copied - } - - /** - * Receives a captured value from the instrument and applies it to the current aggregator value. - * - * @param val, the raw value used in aggregation - */ - void update(T val) override - { - this->mu_.lock(); - this->values_[0] = val; - current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); - this->mu_.unlock(); - } - - /** - * Checkpoints the current value. This function will overwrite the current checkpoint with the - * current value. - * - * @return none - */ - - void checkpoint() override - { - this->mu_.lock(); - - this->checkpoint_ = this->values_; - - // Reset the values to default - this->values_[0] = 0; - checkpoint_timestamp_ = current_timestamp_; - current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); - - this->mu_.unlock(); - } - - /** - * Merges two Gauge aggregators together - * - * @param other the aggregator to merge with this aggregator - */ - void merge(GaugeAggregator other) - { - if (this->kind_ == other.kind_) - { - this->mu_.lock(); - // First merge values - this->values_[0] = other.values_[0]; - // Now merge checkpoints - this->checkpoint_[0] = other.checkpoint_[0]; - current_timestamp_ = core::SystemTimestamp(std::chrono::system_clock::now()); - this->mu_.unlock(); - } - else - { - // Log error - return; - } - } - - /** - * @return the value of the latest checkpoint - */ - std::vector get_checkpoint() override { return this->checkpoint_; } - - /** - * @return the latest checkpointed timestamp - */ - core::SystemTimestamp get_checkpoint_timestamp() override { return checkpoint_timestamp_; } - - /** - * @return the values_ vector stored in this aggregator - */ - std::vector get_values() override { return this->values_; } - - /** - * @return the timestamp of when the last value recorded - */ - core::SystemTimestamp get_timestamp() { return current_timestamp_; } - -private: - core::SystemTimestamp current_timestamp_; - core::SystemTimestamp checkpoint_timestamp_; -}; -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h deleted file mode 100644 index 78b024eaec..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h +++ /dev/null @@ -1,197 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include "opentelemetry/metrics/instrument.h" -#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" -#include "opentelemetry/version.h" - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ - -template -class HistogramAggregator final : public Aggregator -{ - -public: - /** - * Constructor for the histogram aggregator. A sorted vector of boundaries is expected and - * boundaries are doubles regardless of the aggregator's templated data type. - * - * Sum is stored in values_[0] - * Count is stored in position_[1] - */ - HistogramAggregator(metrics_api::InstrumentKind kind, std::vector boundaries) - { - if (!std::is_sorted(boundaries.begin(), boundaries.end())) - { -#if __EXCEPTIONS - throw std::invalid_argument("Histogram boundaries must be monotonic."); -#else - std::terminate(); -#endif - } - this->kind_ = kind; - this->agg_kind_ = AggregatorKind::Histogram; - boundaries_ = boundaries; - this->values_ = std::vector(2, 0); - this->checkpoint_ = std::vector(2, 0); - bucketCounts_ = std::vector(boundaries_.size() + 1, 0); - bucketCounts_ckpt_ = std::vector(boundaries_.size() + 1, 0); - } - - /** - * Recieves a captured value from the instrument and inserts it into the current histogram counts. - * - * Depending on the use case, a linear search or binary search based implementation may be - * preferred. In uniformly distributed datasets, linear search outperforms binary search until 512 - * buckets. However, if the distribution is strongly skewed right (for example server latency - * where most values may be <10ms but the range is from 0 - 1000 ms), a linear search could be - * superior even with more than 500 buckets as almost all values inserted would be at the - * beginning of the boundaries array and thus found more quickly through linear search. - * - * @param val, the raw value used in aggregation - * @return none - */ - void update(T val) override - { - int bucketID = boundaries_.size(); - for (size_t i = 0; i < boundaries_.size(); i++) - { - if (val < boundaries_[i]) // concurrent read is thread-safe - { - bucketID = i; - break; - } - } - - // Alternate implementation with binary search - // auto pos = std::lower_bound (boundaries_.begin(), boundaries_.end(), val); - // bucketCounts_[pos-boundaries_.begin()] += 1; - - this->mu_.lock(); - this->values_[0] += val; - this->values_[1] += 1; - bucketCounts_[bucketID] += 1; - this->mu_.unlock(); - } - - /** - * Checkpoints the current value. This function will overwrite the current checkpoint with the - * current value. - * - * @param none - * @return none - */ - void checkpoint() override - { - this->checkpoint_ = this->values_; - this->values_[0] = 0; - this->values_[1] = 0; - bucketCounts_ckpt_ = bucketCounts_; - std::fill(bucketCounts_.begin(), bucketCounts_.end(), 0); - } - - /** - * Merges the values of two aggregators in a semantically accurate manner. - * A histogram aggregator can only be merged with another histogram aggregator that has the same - * boudnaries. A histogram merge first adds the sum and count values then iterates over the adds - * the bucket counts element by element. - * - * @param other, the aggregator with merge with - * @return none - */ - void merge(HistogramAggregator other) - { - this->mu_.lock(); - - // Ensure that incorrect types are not merged - if (this->agg_kind_ != other.agg_kind_) - { -#if __EXCEPTIONS - throw std::invalid_argument("Aggregators of different types cannot be merged."); -#else - std::terminate(); -#endif - // Reject histogram merges with differing boundary vectors - } - else if (other.boundaries_ != this->boundaries_) - { -#if __EXCEPTIONS - throw std::invalid_argument("Histogram boundaries do not match."); -#else - std::terminate(); -#endif - } - - this->values_[0] += other.values_[0]; - this->values_[1] += other.values_[1]; - - for (size_t i = 0; i < bucketCounts_.size(); i++) - { - bucketCounts_[i] += other.bucketCounts_[i]; - bucketCounts_ckpt_[i] += other.bucketCounts_ckpt_[i]; - } - this->mu_.unlock(); - } - - /** - * Returns the checkpointed value - * - * @param none - * @return the value of the checkpoint - */ - std::vector get_checkpoint() override { return this->checkpoint_; } - - /** - * Returns the current values - * - * @param none - * @return the present aggregator values - */ - std::vector get_values() override { return this->values_; } - - /** - * Returns the bucket boundaries specified at this aggregator's creation. - * - * @param none - * @return the aggregator boundaries - */ - virtual std::vector get_boundaries() override { return boundaries_; } - - /** - * Returns the current counts for each bucket . - * - * @param none - * @return the aggregator bucket counts - */ - virtual std::vector get_counts() override { return bucketCounts_ckpt_; } - - HistogramAggregator(const HistogramAggregator &cp) - { - this->values_ = cp.values_; - this->checkpoint_ = cp.checkpoint_; - this->kind_ = cp.kind_; - this->agg_kind_ = cp.agg_kind_; - boundaries_ = cp.boundaries_; - bucketCounts_ = cp.bucketCounts_; - bucketCounts_ckpt_ = cp.bucketCounts_ckpt_; - // use default initialized mutex as they cannot be copied - } - -private: - std::vector boundaries_; - std::vector bucketCounts_; - std::vector bucketCounts_ckpt_; -}; - -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h b/sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h deleted file mode 100644 index b47cf0df06..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once - -#include "opentelemetry/metrics/instrument.h" -#include "opentelemetry/sdk/metrics/aggregator/aggregator.h" -#include "opentelemetry/version.h" - -#include -#include -#include - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ -const int MinValueIndex = 0; -const int MaxValueIndex = 1; -const int SumValueIndex = 2; -const int CountValueIndex = 3; -/** - * This aggregator stores and maintains a vector of - * type T where the contents in the vector are made - * up of the minimum value recorded to this instrument, - * the maximum value, the sum of all values, and the - * count of all values. - * - * @tparam T the type of values stored in this aggregator. - */ -template -class MinMaxSumCountAggregator : public Aggregator -{ -public: - explicit MinMaxSumCountAggregator(metrics_api::InstrumentKind kind) - { - static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - this->kind_ = kind; - this->values_ = std::vector(4, 0); // {min, max, sum, count} - this->checkpoint_ = this->values_; - this->agg_kind_ = AggregatorKind::MinMaxSumCount; - } - - ~MinMaxSumCountAggregator() = default; - - MinMaxSumCountAggregator(const MinMaxSumCountAggregator &cp) - { - this->values_ = cp.values_; - this->checkpoint_ = cp.checkpoint_; - this->kind_ = cp.kind_; - this->agg_kind_ = cp.agg_kind_; - // use default initialized mutex as they cannot be copied - } - - /** - * Receives a captured value from the instrument and applies it to the current aggregator value. - * - * @param val, the raw value used in aggregation - */ - void update(T val) override - { - this->mu_.lock(); - - if (this->values_[CountValueIndex] == 0 || val < this->values_[MinValueIndex]) // set min - this->values_[MinValueIndex] = val; - if (this->values_[CountValueIndex] == 0 || val > this->values_[MaxValueIndex]) // set max - this->values_[MaxValueIndex] = val; - - this->values_[SumValueIndex] += val; // compute sum - this->values_[CountValueIndex]++; // increment count - - this->mu_.unlock(); - } - - /** - * Checkpoints the current value. This function will overwrite the current checkpoint with the - * current value. - * - */ - void checkpoint() override - { - this->mu_.lock(); - this->checkpoint_ = this->values_; - // Reset the values - this->values_[MinValueIndex] = 0; - this->values_[MaxValueIndex] = 0; - this->values_[SumValueIndex] = 0; - this->values_[CountValueIndex] = 0; - this->mu_.unlock(); - } - - /** - * Merges two MinMaxSumCount aggregators together - * - * @param other the aggregator to merge with this aggregator - */ - void merge(const MinMaxSumCountAggregator &other) - { - if (this->kind_ == other.kind_) - { - this->mu_.lock(); - // First merge values - // set min - if (this->values_[CountValueIndex] == 0 || - other.values_[MinValueIndex] < this->values_[MinValueIndex]) - this->values_[MinValueIndex] = other.values_[MinValueIndex]; - // set max - if (this->values_[CountValueIndex] == 0 || - other.values_[MaxValueIndex] > this->values_[MaxValueIndex]) - this->values_[MaxValueIndex] = other.values_[MaxValueIndex]; - // set sum - this->values_[SumValueIndex] += other.values_[SumValueIndex]; - // set count - this->values_[CountValueIndex] += other.values_[CountValueIndex]; - - // Now merge checkpoints - if (this->checkpoint_[CountValueIndex] == 0 || - other.checkpoint_[MinValueIndex] < this->checkpoint_[MinValueIndex]) - this->checkpoint_[MinValueIndex] = other.checkpoint_[MinValueIndex]; - // set max - if (this->checkpoint_[CountValueIndex] == 0 || - other.checkpoint_[MaxValueIndex] > this->checkpoint_[MaxValueIndex]) - this->checkpoint_[MaxValueIndex] = other.checkpoint_[MaxValueIndex]; - // set sum - this->checkpoint_[SumValueIndex] += other.checkpoint_[SumValueIndex]; - // set count - this->checkpoint_[CountValueIndex] += other.checkpoint_[CountValueIndex]; - - this->mu_.unlock(); - } - else - { - // Log error - return; - } - } - - /** - * Returns the checkpointed value - * - * @return the value of the checkpoint - */ - std::vector get_checkpoint() override { return this->checkpoint_; } - - /** - * Returns the values currently held by the aggregator - * - * @return the values held by the aggregator - */ - std::vector get_values() override { return this->values_; } -}; -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/meter.h b/sdk/include/opentelemetry/sdk/metrics/meter.h index 9a66adb6d9..2acbc76d3c 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter.h @@ -4,7 +4,6 @@ #include "opentelemetry/version.h" #include -#include OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -14,16 +13,8 @@ namespace metrics class Meter final : public opentelemetry::metrics::Meter, public std::enable_shared_from_this { public: - explicit Meter(std::string library_name, std::string library_version) - { - library_name_ = library_name; - library_version_ = library_version; - } -private: - std::string library_name_; - std::string library_version_; }; -} // namespace metrics +} // namespace trace } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h index 4112d14b8f..7c3fbab4d8 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -1,11 +1,10 @@ #pragma once -#include "opentelemetry/metrics/meter_provider.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/metrics/meter_provider.h" #include -#include OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -18,7 +17,7 @@ class MeterProvider final : public opentelemetry::metrics::MeterProvider /** * Initialize a new meter provider */ - explicit MeterProvider(std::string library_name = "", std::string library_version = "") noexcept; + explicit MeterProvider() noexcept; opentelemetry::nostd::shared_ptr GetMeter( nostd::string_view library_name, diff --git a/sdk/include/opentelemetry/sdk/trace/recordable.h b/sdk/include/opentelemetry/sdk/trace/recordable.h index 68124db0e6..dcf9a50c7a 100644 --- a/sdk/include/opentelemetry/sdk/trace/recordable.h +++ b/sdk/include/opentelemetry/sdk/trace/recordable.h @@ -3,13 +3,13 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" -#include "opentelemetry/sdk/common/empty_attributes.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/key_value_iterable.h" #include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/version.h" +#include "opentelemetry/sdk/common/empty_attributes.h" #include diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index 2308ae7080..f0ab885626 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -2,9 +2,9 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/trace/span.h" -#include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/version.h" +#include "opentelemetry/trace/span_context.h" #include #include diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h index 0137a6b181..5a11f1c10c 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h @@ -18,12 +18,11 @@ class AlwaysOnSampler : public Sampler /** * @return Always return Decision RECORD_AND_SAMPLE */ - inline SamplingResult ShouldSample( - const trace_api::SpanContext * /*parent_context*/, - trace_api::TraceId /*trace_id*/, - nostd::string_view /*name*/, - trace_api::SpanKind /*span_kind*/, - const trace_api::KeyValueIterable & /*attributes*/) noexcept override + inline SamplingResult ShouldSample(const trace_api::SpanContext * /*parent_context*/, + trace_api::TraceId /*trace_id*/, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept override { return {Decision::RECORD_AND_SAMPLE, nullptr}; } diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h index ce16f7e9c6..95cf9afa37 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h @@ -22,11 +22,11 @@ class ParentOrElseSampler : public Sampler * delegateSampler for root spans * @return Returns NOT_RECORD always */ - SamplingResult ShouldSample(const trace_api::SpanContext *parent_context, + SamplingResult ShouldSample(const trace_api::SpanContext * parent_context, trace_api::TraceId trace_id, nostd::string_view name, trace_api::SpanKind span_kind, - const trace_api::KeyValueIterable &attributes) noexcept override; + const trace_api::KeyValueIterable & attributes) noexcept override; /** * @return Description MUST be ParentOrElse{delegate_sampler_.getDescription()} diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/probability.h b/sdk/include/opentelemetry/sdk/trace/samplers/probability.h index 9ad8e7f0ea..aa585409a4 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/probability.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/probability.h @@ -29,11 +29,12 @@ class ProbabilitySampler : public Sampler * is used as a pseudorandom value in conjunction with the predefined * threshold to determine whether this trace should be sampled */ - SamplingResult ShouldSample(const trace_api::SpanContext *parent_context, - trace_api::TraceId trace_id, - nostd::string_view /*name*/, - trace_api::SpanKind /*span_kind*/, - const trace_api::KeyValueIterable & /*attributes*/) noexcept override; + SamplingResult ShouldSample( + const trace_api::SpanContext *parent_context, + trace_api::TraceId trace_id, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept override; /** * @return Description MUST be ProbabilitySampler{0.000100} diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index e6f5547f2d..c2b0d69e0c 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -3,8 +3,8 @@ #include "opentelemetry/sdk/common/atomic_shared_ptr.h" #include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/samplers/always_on.h" -#include "opentelemetry/trace/noop.h" #include "opentelemetry/trace/tracer.h" +#include "opentelemetry/trace/noop.h" #include "opentelemetry/version.h" #include diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 7c009a7bab..97a0533e86 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -5,8 +5,8 @@ namespace sdk { namespace metrics { -MeterProvider::MeterProvider(std::string library_name, std::string library_version) noexcept - : meter_(new Meter(library_name, library_version)) +MeterProvider::MeterProvider() noexcept + : meter_(new Meter) {} opentelemetry::nostd::shared_ptr MeterProvider::GetMeter( diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index d37699916e..1e6d302461 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -1,3 +1,2 @@ -add_library( - opentelemetry_trace tracer_provider.cc tracer.cc span.cc - samplers/parent_or_else.cc samplers/probability.cc) +add_library(opentelemetry_trace tracer_provider.cc tracer.cc span.cc + samplers/parent_or_else.cc samplers/probability.cc) diff --git a/sdk/src/trace/samplers/parent_or_else.cc b/sdk/src/trace/samplers/parent_or_else.cc index 29026a0167..f3b926c2b6 100644 --- a/sdk/src/trace/samplers/parent_or_else.cc +++ b/sdk/src/trace/samplers/parent_or_else.cc @@ -22,7 +22,7 @@ SamplingResult ParentOrElseSampler::ShouldSample( // If no parent (root span) exists returns the result of the delegateSampler return delegate_sampler_->ShouldSample(parent_context, trace_id, name, span_kind, attributes); } - + // If parent exists: if (parent_context->IsSampled()) { diff --git a/sdk/src/trace/samplers/probability.cc b/sdk/src/trace/samplers/probability.cc index 0fd45644e4..0038ed11fb 100644 --- a/sdk/src/trace/samplers/probability.cc +++ b/sdk/src/trace/samplers/probability.cc @@ -23,50 +23,49 @@ namespace trace_api = opentelemetry::trace; namespace { -/** - * Converts a probability in [0, 1] to a threshold in [0, UINT64_MAX] - * - * @param probability a required value top be converted to uint64_t. is - * bounded by 1 >= probability >= 0. - * @return Returns threshold value computed after converting probability to - * uint64_t datatype - */ -uint64_t CalculateThreshold(double probability) noexcept -{ - if (probability <= 0.0) - return 0; - if (probability >= 1.0) - return UINT64_MAX; - - // We can't directly return probability * UINT64_MAX. - // - // UINT64_MAX is (2^64)-1, but as a double rounds up to 2^64. - // For probabilities >= 1-(2^-54), the product wraps to zero! - // Instead, calculate the high and low 32 bits separately. - const double product = UINT32_MAX * probability; - double hi_bits, lo_bits = ldexp(modf(product, &hi_bits), 32) + product; - return (static_cast(hi_bits) << 32) + static_cast(lo_bits); -} + /** + * Converts a probability in [0, 1] to a threshold in [0, UINT64_MAX] + * + * @param probability a required value top be converted to uint64_t. is + * bounded by 1 >= probability >= 0. + * @return Returns threshold value computed after converting probability to + * uint64_t datatype + */ + uint64_t CalculateThreshold(double probability) noexcept + { + if (probability <= 0.0) return 0; + if (probability >= 1.0) return UINT64_MAX; + + // We can't directly return probability * UINT64_MAX. + // + // UINT64_MAX is (2^64)-1, but as a double rounds up to 2^64. + // For probabilities >= 1-(2^-54), the product wraps to zero! + // Instead, calculate the high and low 32 bits separately. + const double product = UINT32_MAX * probability; + double hi_bits, lo_bits = ldexp(modf(product, &hi_bits), 32) + product; + return (static_cast(hi_bits) << 32) + + static_cast(lo_bits); + } -/** - * @param trace_id a required value to be converted to uint64_t. trace_id must - * at least 8 bytes long - * @return Returns threshold value computed after converting trace_id to - * uint64_t datatype - */ -uint64_t CalculateThresholdFromBuffer(const trace_api::TraceId &trace_id) noexcept -{ - // We only use the first 8 bytes of TraceId. - static_assert(trace_api::TraceId::kSize >= 8, "TraceID must be at least 8 bytes long."); + /** + * @param trace_id a required value to be converted to uint64_t. trace_id must + * at least 8 bytes long + * @return Returns threshold value computed after converting trace_id to + * uint64_t datatype + */ + uint64_t CalculateThresholdFromBuffer(const trace_api::TraceId& trace_id) noexcept + { + // We only use the first 8 bytes of TraceId. + static_assert(trace_api::TraceId::kSize >= 8, "TraceID must be at least 8 bytes long."); - uint64_t res = 0; - std::memcpy(&res, &trace_id, 8); + uint64_t res = 0; + std::memcpy(&res, &trace_id, 8); - double probability = (double)res / UINT64_MAX; + double probability = (double) res / UINT64_MAX; - return CalculateThreshold(probability); -} -} // namespace + return CalculateThreshold(probability); + } +} // namespace OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -74,43 +73,36 @@ namespace sdk namespace trace { ProbabilitySampler::ProbabilitySampler(double probability) - : threshold_(CalculateThreshold(probability)) +: threshold_(CalculateThreshold(probability)) { - if (probability > 1.0) - probability = 1.0; - if (probability < 0.0) - probability = 0.0; - description_ = "ProbabilitySampler{" + std::to_string(probability) + "}"; -} + if (probability > 1.0) probability = 1.0; + if (probability < 0.0) probability = 0.0; + description_ = "ProbabilitySampler{" + std::to_string(probability) + "}"; + } SamplingResult ProbabilitySampler::ShouldSample( - const trace_api::SpanContext *parent_context, - trace_api::TraceId trace_id, - nostd::string_view /*name*/, - trace_api::SpanKind /*span_kind*/, - const trace_api::KeyValueIterable & /*attributes*/) noexcept + const trace_api::SpanContext *parent_context, + trace_api::TraceId trace_id, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept { - if (parent_context && !parent_context->HasRemoteParent()) - { - if (parent_context->IsSampled()) - { - return {Decision::RECORD_AND_SAMPLE, nullptr}; - } - else - { - return {Decision::NOT_RECORD, nullptr}; + if (parent_context && !parent_context->HasRemoteParent()) { + if (parent_context->IsSampled()) { + return { Decision::RECORD_AND_SAMPLE, nullptr }; + } else { + return { Decision::NOT_RECORD, nullptr }; } } - if (threshold_ == 0) - return {Decision::NOT_RECORD, nullptr}; + if (threshold_ == 0) return { Decision::NOT_RECORD, nullptr }; if (CalculateThresholdFromBuffer(trace_id) <= threshold_) { - return {Decision::RECORD_AND_SAMPLE, nullptr}; + return { Decision::RECORD_AND_SAMPLE, nullptr }; } - return {Decision::NOT_RECORD, nullptr}; + return { Decision::NOT_RECORD, nullptr }; } nostd::string_view ProbabilitySampler::GetDescription() const noexcept diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD index d24acd3e58..e2d5c5cb71 100644 --- a/sdk/test/metrics/BUILD +++ b/sdk/test/metrics/BUILD @@ -1,25 +1,3 @@ -cc_test( - name = "gauge_aggregator_test", - srcs = [ - "gauge_aggregator_test.cc", - ], - deps = [ - "//sdk/src/metrics", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "min_max_sum_count_aggregator_test", - srcs = [ - "min_max_sum_count_aggregator_test.cc", - ], - deps = [ - "//sdk/src/metrics", - "@com_google_googletest//:gtest_main", - ], -) - cc_test( name = "meter_provider_sdk_test", srcs = [ @@ -30,36 +8,3 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) - -cc_test( - name = "counter_aggregator_test", - srcs = [ - "counter_aggregator_test.cc", - ], - deps = [ - "//sdk/src/metrics", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "exact_aggregator_test", - srcs = [ - "exact_aggregator_test.cc", - ], - deps = [ - "//sdk/src/metrics", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "histogram_aggregator_test", - srcs = [ - "histogram_aggregator_test.cc", - ], - deps = [ - "//sdk/src/metrics", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index 54c39e786c..800b57557a 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -1,10 +1,6 @@ -foreach( - testname - meter_provider_sdk_test gauge_aggregator_test - min_max_sum_count_aggregator_test exact_aggregator_test - counter_aggregator_test histogram_aggregator_test) +foreach(testname meter_provider_sdk_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics) + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common opentelemetry_metrics) gtest_add_tests(TARGET ${testname} TEST_PREFIX metrics. TEST_LIST ${testname}) endforeach() diff --git a/sdk/test/metrics/counter_aggregator_test.cc b/sdk/test/metrics/counter_aggregator_test.cc deleted file mode 100644 index 1e2b1dce8c..0000000000 --- a/sdk/test/metrics/counter_aggregator_test.cc +++ /dev/null @@ -1,115 +0,0 @@ -#include "opentelemetry/sdk/metrics/aggregator/counter_aggregator.h" - -#include -#include -#include - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ - -TEST(CounterAggregator, NoUpdates) -{ - CounterAggregator alpha(metrics_api::InstrumentKind::Counter); - - EXPECT_EQ(alpha.get_checkpoint().size(), 1); - EXPECT_EQ(alpha.get_checkpoint()[0], 0); - - alpha.checkpoint(); - EXPECT_EQ(alpha.get_checkpoint().size(), 1); - EXPECT_EQ(alpha.get_checkpoint()[0], 0); -} - -TEST(CounterAggregator, Update) -{ - CounterAggregator alpha(metrics_api::InstrumentKind::Counter); - CounterAggregator beta(metrics_api::InstrumentKind::Counter); - - for (int i = 0; i < 123456; i++) - { - alpha.update(1); - } - - int sum = 0; - for (int i = 0; i < 100; i++) - { - int tmp = std::rand(); - beta.update(tmp); - sum += tmp; - } - - EXPECT_EQ(alpha.get_checkpoint()[0], 0); // checkpoint shouldn't change even with updates - EXPECT_EQ(beta.get_checkpoint()[0], 0); - - alpha.checkpoint(); - beta.checkpoint(); - - EXPECT_EQ(alpha.get_checkpoint()[0], 123456); - EXPECT_EQ(beta.get_checkpoint()[0], sum); - - alpha.update(15); - alpha.checkpoint(); - EXPECT_EQ(alpha.get_checkpoint()[0], 15); // reset to 0 after first checkpoint call -} - -// callback update function used to test concurrent calls -void incrementingCallback(Aggregator &agg) -{ - for (int i = 0; i < 2000000; i++) - { - agg.update(1); - } -} - -TEST(CounterAggregator, Concurrency) -{ - CounterAggregator alpha(metrics_api::InstrumentKind::Counter); - - // spawn new threads that initiate the callback - std::thread first(incrementingCallback, std::ref(alpha)); - std::thread second(incrementingCallback, std::ref(alpha)); - - first.join(); - second.join(); - - alpha.checkpoint(); - - // race conditions result in values below 2*2000000 - EXPECT_EQ(alpha.get_checkpoint()[0], 2 * 2000000); -} - -TEST(CounterAggregator, Merge) -{ - CounterAggregator alpha(metrics_api::InstrumentKind::Counter); - CounterAggregator beta(metrics_api::InstrumentKind::Counter); - - alpha.merge(beta); - - alpha.checkpoint(); - EXPECT_EQ(alpha.get_checkpoint()[0], 0); // merge with no updates - - for (int i = 0; i < 500; i++) - { - alpha.update(1); - } - - for (int i = 0; i < 700; i++) - { - beta.update(1); - } - - alpha.merge(beta); - alpha.checkpoint(); - EXPECT_EQ(alpha.get_checkpoint()[0], 1200); - - // HistogramAggregator gamma(metrics_api::BoundInstrumentKind::BoundValueRecorder); - // ASSERT_THROW(alpha.merge(gamma), AggregatorMismatch); -} - -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/metrics/exact_aggregator_test.cc b/sdk/test/metrics/exact_aggregator_test.cc deleted file mode 100644 index be32b87704..0000000000 --- a/sdk/test/metrics/exact_aggregator_test.cc +++ /dev/null @@ -1,217 +0,0 @@ -#include -#include - -#include "opentelemetry/sdk/metrics/aggregator/exact_aggregator.h" - -using namespace opentelemetry::sdk::metrics; - -TEST(ExactAggregatorOrdered, Update) -{ - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - std::vector correct; - - ASSERT_EQ(agg.get_values(), correct); - - agg.update(1); - correct.push_back(1); - - ASSERT_EQ(agg.get_values(), std::vector{1}); - - for (int i = 2; i <= 5; ++i) - { - correct.push_back(i); - agg.update(i); - } - ASSERT_EQ(agg.get_values(), correct); -} - -TEST(ExactAggregatorOrdered, Checkpoint) -{ - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - std::vector correct; - - ASSERT_EQ(agg.get_checkpoint(), correct); - - agg.update(1); - correct.push_back(1); - agg.checkpoint(); - - ASSERT_EQ(agg.get_checkpoint(), correct); -} - -TEST(ExactAggregatorOrdered, Merge) -{ - ExactAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); - ExactAggregator agg2(opentelemetry::metrics::InstrumentKind::Counter); - - agg1.update(1); - agg2.update(2); - agg1.merge(agg2); - - std::vector correct{1, 2}; - - ASSERT_EQ(agg1.get_values(), correct); -} - -TEST(ExactAggregatorOrdered, BadMerge) -{ - // This verifies that we encounter and error when we try to merge - // two aggregators of different numeric types together. - ExactAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); - ExactAggregator agg2(opentelemetry::metrics::InstrumentKind::ValueRecorder); - - agg1.update(1); - agg2.update(2); - - agg1.merge(agg2); - - // Verify that the aggregators did NOT merge - std::vector correct{1}; - ASSERT_EQ(agg1.get_values(), correct); -} - -TEST(ExactAggregatorOrdered, Types) -{ - // This test verifies that we do not encounter any errors when - // using various numeric types. - ExactAggregator agg_int(opentelemetry::metrics::InstrumentKind::Counter); - ExactAggregator agg_long(opentelemetry::metrics::InstrumentKind::Counter); - ExactAggregator agg_float(opentelemetry::metrics::InstrumentKind::Counter); - ExactAggregator agg_double(opentelemetry::metrics::InstrumentKind::Counter); - - for (int i = 1; i <= 5; ++i) - { - agg_int.update(i); - agg_long.update(i); - } - - for (float i = 1.0; i <= 5.0; i += 1) - { - agg_float.update(i); - agg_double.update(i); - } - - std::vector correct_int{1, 2, 3, 4, 5}; - std::vector correct_long{1, 2, 3, 4, 5}; - std::vector correct_float{1.0, 2.0, 3.0, 4.0, 5.0}; - std::vector correct_double{1.0, 2.0, 3.0, 4.0, 5.0}; - - ASSERT_EQ(agg_int.get_values(), correct_int); - ASSERT_EQ(agg_long.get_values(), correct_long); - ASSERT_EQ(agg_float.get_values(), correct_float); - ASSERT_EQ(agg_double.get_values(), correct_double); -} - -TEST(ExactAggregatorQuant, Update) -{ - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); - - std::vector correct; - - ASSERT_EQ(agg.get_values(), correct); - - agg.update(1); - correct.push_back(1); - - ASSERT_EQ(agg.get_values(), std::vector{1}); - - for (int i = 2; i <= 5; ++i) - { - correct.push_back(i); - agg.update(i); - } - ASSERT_EQ(agg.get_values(), correct); -} - -TEST(ExactAggregatorQuant, Checkpoint) -{ - // This test verifies that the aggregator updates correctly when - // quantile estimation is turned on. - - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); - - std::vector correct; - - ASSERT_EQ(agg.get_checkpoint(), correct); - - agg.update(1); - agg.update(0); - agg.update(-1); - - // The vector MUST be sorted when checkpointed - correct.push_back(-1); - correct.push_back(0); - correct.push_back(1); - agg.checkpoint(); - - ASSERT_EQ(agg.get_checkpoint(), correct); -} - -TEST(ExactAggregatorQuant, Quantile) -{ - // This test verifies that the quantile estimation function returns - // the correct values. - - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); - - std::vector tmp{3, 9, 42, 57, 163, 210, 272, 300}; - for (int i : tmp) - { - agg.update(i); - } - agg.checkpoint(); - ASSERT_EQ(agg.get_quantiles(.25), 42); - ASSERT_EQ(agg.get_quantiles(0.5), 163); - ASSERT_EQ(agg.get_quantiles(0.75), 272); -} - -TEST(ExactAggregatorInOrder, Quantile) -{ - // This test verifies that if the user has an exact aggregator in "in-order" mode - // an exception will be thrown if they call the quantile() function. - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - std::vector tmp{3, 9, 42, 57, 163, 210, 272, 300}; - for (int i : tmp) - { - agg.update(i); - } - agg.checkpoint(); -#if __EXCEPTIONS - ASSERT_THROW(agg.get_quantiles(0.5), std::domain_error); -#else -#endif -} - -void callback(ExactAggregator &agg) -{ - for (int i = 1; i <= 10000; ++i) - { - agg.update(i); - } -} - -TEST(ExactAggregatorQuant, Concurrency) -{ - // This test checks that the aggregator updates appropriately - // when called in a multi-threaded context. - ExactAggregator agg(opentelemetry::metrics::InstrumentKind::Counter, true); - - std::thread first(&callback, std::ref(agg)); - std::thread second(&callback, std::ref(agg)); - - first.join(); - second.join(); - - std::vector correct; - for (int i = 1; i <= 10000; ++i) - { - correct.push_back(i); - correct.push_back(i); - } - agg.checkpoint(); - - ASSERT_EQ(agg.get_checkpoint(), correct); -} \ No newline at end of file diff --git a/sdk/test/metrics/gauge_aggregator_test.cc b/sdk/test/metrics/gauge_aggregator_test.cc deleted file mode 100644 index 7370d78f70..0000000000 --- a/sdk/test/metrics/gauge_aggregator_test.cc +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include - -#include "opentelemetry/sdk/metrics/aggregator/gauge_aggregator.h" - -using namespace opentelemetry::sdk::metrics; - -TEST(GaugeAggregator, Update) -{ - // This tests that the aggregator updates the maintained value correctly - // after a call to the update() function. - auto agg = new GaugeAggregator(opentelemetry::metrics::InstrumentKind::Counter); - - // Verify default value - ASSERT_EQ(agg->get_values()[0], 0); - - // Verify that the value updates correctly - agg->update(1); - ASSERT_EQ(agg->get_values()[0], 1); - - // Verify that the value continually updates correctly - for (int i = 0; i < 10; ++i) - { - agg->update(i); - } - ASSERT_EQ(agg->get_values()[0], 9); - delete agg; -} - -TEST(GaugeAggregator, Checkpoint) -{ - // This tests that the aggregator correctly updates the - // checkpoint_ value after a call to update() followed - // by a call to checkpoint(). - GaugeAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - // Verify default checkpoint, before updates - ASSERT_EQ(agg.get_checkpoint()[0], 0); - - agg.update(10); - agg.checkpoint(); - - // Verify that the new checkpoint contains the update value - ASSERT_EQ(agg.get_checkpoint()[0], 10); -} - -TEST(GaugeAggregator, Merge) -{ - // This tests that the values_ vector is updated correctly after - // two aggregators are merged together. - GaugeAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); - GaugeAggregator agg2(opentelemetry::metrics::InstrumentKind::Counter); - - agg1.update(1); - agg2.update(2); - - agg1.merge(agg2); - - // Verify that the aggregators merged and the value was updated correctly - ASSERT_EQ(agg1.get_values()[0], 2); -} - -TEST(GaugeAggregator, BadMerge) -{ - // This verifies that we encounter and error when we try to merge - // two aggregators of different numeric types together. - GaugeAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); - GaugeAggregator agg2(opentelemetry::metrics::InstrumentKind::ValueRecorder); - - agg1.update(1); - agg2.update(2); - agg1.merge(agg2); - - // Verify that the aggregators did NOT merge - std::vector correct{1}; - ASSERT_EQ(agg1.get_values(), correct); -} - -TEST(GaugeAggregator, Types) -{ - // This test verifies that we do not encounter any errors when - // using various numeric types. - GaugeAggregator agg_int(opentelemetry::metrics::InstrumentKind::Counter); - GaugeAggregator agg_long(opentelemetry::metrics::InstrumentKind::Counter); - GaugeAggregator agg_float(opentelemetry::metrics::InstrumentKind::Counter); - GaugeAggregator agg_double(opentelemetry::metrics::InstrumentKind::Counter); - - for (int i = 1; i <= 10; ++i) - { - agg_int.update(i); - agg_long.update(i); - } - - for (float i = 1.0; i <= 10.0; i += 1) - { - agg_float.update(i); - agg_double.update(i); - } - - ASSERT_EQ(agg_int.get_values()[0], 10); - ASSERT_EQ(agg_long.get_values()[0], 10); - ASSERT_EQ(agg_float.get_values()[0], 10.0); - ASSERT_EQ(agg_double.get_values()[0], 10.0); -} - -static void callback(GaugeAggregator &agg) -{ - for (int i = 1; i <= 10000; ++i) - { - agg.update(i); - } -} - -TEST(GaugeAggregator, Concurrency) -{ - // This test checks that the aggregator updates appropriately - // when called in a multi-threaded context. - GaugeAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - std::thread first(&callback, std::ref(agg)); - std::thread second(&callback, std::ref(agg)); - - first.join(); - second.join(); - - ASSERT_EQ(agg.get_values()[0], 10000); -} \ No newline at end of file diff --git a/sdk/test/metrics/histogram_aggregator_test.cc b/sdk/test/metrics/histogram_aggregator_test.cc deleted file mode 100644 index 146c552bb0..0000000000 --- a/sdk/test/metrics/histogram_aggregator_test.cc +++ /dev/null @@ -1,167 +0,0 @@ -#include "opentelemetry/sdk/metrics/aggregator/histogram_aggregator.h" - -#include -#include -#include -#include -// #include - -namespace metrics_api = opentelemetry::metrics; - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ - -// Test updating with a uniform set of updates -TEST(Histogram, Uniform) -{ - std::vector boundaries{10, 20, 30, 40, 50}; - HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); - - EXPECT_EQ(alpha.get_aggregator_kind(), AggregatorKind::Histogram); - - alpha.checkpoint(); - EXPECT_EQ(alpha.get_checkpoint().size(), 2); - EXPECT_EQ(alpha.get_counts().size(), 6); - - for (int i = 0; i < 60; i++) - { - alpha.update(i); - } - - alpha.checkpoint(); - - EXPECT_EQ(alpha.get_checkpoint()[0], 1770); - EXPECT_EQ(alpha.get_checkpoint()[1], 60); - - std::vector correct = {10, 10, 10, 10, 10, 10}; - EXPECT_EQ(alpha.get_counts(), correct); -} - -// Test updating with a normal distribution -TEST(Histogram, Normal) -{ - std::vector boundaries{2, 4, 6, 8, 10, 12}; - HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); - - std::vector vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13}; - for (int i : vals) - { - alpha.update(i); - } - - alpha.checkpoint(); - - EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0)); - EXPECT_EQ(alpha.get_checkpoint()[1], vals.size()); - - std::vector correct = {1, 2, 3, 4, 3, 2, 1}; - EXPECT_EQ(alpha.get_counts(), correct); -} - -TEST(Histogram, Merge) -{ - std::vector boundaries{2, 4, 6, 8, 10, 12}; - HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); - HistogramAggregator beta(metrics_api::InstrumentKind::Counter, boundaries); - - std::vector vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13}; - for (int i : vals) - { - alpha.update(i); - } - - std::vector otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15}; - for (int i : otherVals) - { - beta.update(i); - } - - alpha.merge(beta); - alpha.checkpoint(); - - EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) + - std::accumulate(otherVals.begin(), otherVals.end(), 0)); - EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size()); - - std::vector correct = {5, 2, 3, 4, 3, 4, 5}; - EXPECT_EQ(alpha.get_counts(), correct); -} - -// Update callback used to validate multi-threaded performance -void histogramUpdateCallback(Aggregator &agg, std::vector vals) -{ - for (int i : vals) - { - agg.update(i); - } -} - -int randVal() -{ - return rand() % 15; -} - -TEST(Histogram, Concurrency) -{ - std::vector boundaries{2, 4, 6, 8, 10, 12}; - HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, boundaries); - - std::vector vals1(1000); - std::generate(vals1.begin(), vals1.end(), randVal); - - std::vector vals2(1000); - std::generate(vals2.begin(), vals2.end(), randVal); - - std::thread first(histogramUpdateCallback, std::ref(alpha), vals1); - std::thread second(histogramUpdateCallback, std::ref(alpha), vals2); - - first.join(); - second.join(); - - HistogramAggregator beta(metrics_api::InstrumentKind::Counter, boundaries); - - // Timing harness to compare linear and binary insertion - // auto start = std::chrono::system_clock::now(); - for (int i : vals1) - { - beta.update(i); - } - for (int i : vals2) - { - beta.update(i); - } - // auto end = std::chrono::system_clock::now(); - // auto elapsed = std::chrono::duration_cast(end - start); - // std::cout <<"Update time: " < boundaries{2, 4, 6, 8, 10, 12}; - std::vector boundaries2{1, 4, 6, 8, 10, 12}; - std::vector unsortedBoundaries{10, 12, 4, 6, 8}; - EXPECT_ANY_THROW( - HistogramAggregator alpha(metrics_api::InstrumentKind::Counter, unsortedBoundaries)); - - HistogramAggregator beta(metrics_api::InstrumentKind::Counter, boundaries); - HistogramAggregator gamma(metrics_api::InstrumentKind::Counter, boundaries2); - - EXPECT_ANY_THROW(beta.merge(gamma)); -} - -#endif - -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 52a00d6c58..37d27b65c1 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -1,5 +1,5 @@ -#include "opentelemetry/sdk/metrics/meter.h" #include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/meter.h" #include @@ -18,4 +18,5 @@ TEST(MeterProvider, GetMeter) // Should return the same instance each time. ASSERT_EQ(t1, t2); ASSERT_EQ(t1, t3); + } diff --git a/sdk/test/metrics/min_max_sum_count_aggregator_test.cc b/sdk/test/metrics/min_max_sum_count_aggregator_test.cc deleted file mode 100644 index 21d06ddcea..0000000000 --- a/sdk/test/metrics/min_max_sum_count_aggregator_test.cc +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include - -#include "opentelemetry/sdk/metrics/aggregator/min_max_sum_count_aggregator.h" - -using namespace opentelemetry::sdk::metrics; - -TEST(MinMaxSumCountAggregator, Update) -{ - // This tests that the aggregator updates the maintained value correctly - // after a call to the update() function. - MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - auto value_set = agg.get_values(); - ASSERT_EQ(value_set[0], 0); - ASSERT_EQ(value_set[1], 0); - ASSERT_EQ(value_set[2], 0); - ASSERT_EQ(value_set[3], 0); - - // 1 + 2 + 3 + ... + 10 = 55 - for (int i = 1; i <= 10; ++i) - { - agg.update(i); - } - - value_set = agg.get_values(); - ASSERT_EQ(value_set[0], 1); // min - ASSERT_EQ(value_set[1], 10); // max - ASSERT_EQ(value_set[2], 55); // sum - ASSERT_EQ(value_set[3], 10); // count -} - -TEST(MinMaxSumCountAggregator, FirstUpdate) -{ - // This tests that the aggregator appropriately maintains the min and - // max values after a single update call. - MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - agg.update(1); - auto value_set = agg.get_values(); - ASSERT_EQ(value_set[0], 1); // min - ASSERT_EQ(value_set[1], 1); // max - ASSERT_EQ(value_set[2], 1); // sum - ASSERT_EQ(value_set[3], 1); // count -} - -TEST(MinMaxSumCountAggregator, Checkpoint) -{ - // This test verifies that the default checkpoint is set correctly - // and that the checkpoint values update correctly after a call - // to the checkpoint() function. - MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - // Verify that the default checkpoint is set correctly. - auto checkpoint_set = agg.get_checkpoint(); - ASSERT_EQ(checkpoint_set[0], 0); // min - ASSERT_EQ(checkpoint_set[1], 0); // max - ASSERT_EQ(checkpoint_set[2], 0); // sum - ASSERT_EQ(checkpoint_set[3], 0); // count - - // 1 + 2 + 3 + ... + 10 = 55 - for (int i = 1; i <= 10; ++i) - { - agg.update(i); - } - - agg.checkpoint(); - - // Verify that the checkpoint values were updated. - checkpoint_set = agg.get_checkpoint(); - ASSERT_EQ(checkpoint_set[0], 1); // min - ASSERT_EQ(checkpoint_set[1], 10); // max - ASSERT_EQ(checkpoint_set[2], 55); // sum - ASSERT_EQ(checkpoint_set[3], 10); // count - - // Verify that the current values were reset to the default state. - auto value_set = agg.get_values(); - ASSERT_EQ(value_set[0], 0); // min - ASSERT_EQ(value_set[1], 0); // max - ASSERT_EQ(value_set[2], 0); // sum - ASSERT_EQ(value_set[3], 0); // count -} - -TEST(MinMaxSumCountAggregator, Merge) -{ - // This tests that the values_ vector is updated correctly after - // two aggregators are merged together. - MinMaxSumCountAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); - MinMaxSumCountAggregator agg2(opentelemetry::metrics::InstrumentKind::Counter); - - // 1 + 2 + 3 + ... + 10 = 55 - for (int i = 1; i <= 10; ++i) - { - agg1.update(i); - } - - // 1 + 2 + 3 + ... + 20 = 210 - for (int i = 1; i <= 20; ++i) - { - agg2.update(i); - } - - agg1.merge(agg2); - - // Verify that the current values were changed by the merge. - auto value_set = agg1.get_values(); - ASSERT_EQ(value_set[0], 1); // min - ASSERT_EQ(value_set[1], 20); // max - ASSERT_EQ(value_set[2], 265); // sum - ASSERT_EQ(value_set[3], 30); // count -} - -TEST(MinMaxSumCountAggregator, BadMerge) -{ - // This verifies that we encounter and error when we try to merge - // two aggregators of different numeric types together. - MinMaxSumCountAggregator agg1(opentelemetry::metrics::InstrumentKind::Counter); - MinMaxSumCountAggregator agg2(opentelemetry::metrics::InstrumentKind::ValueRecorder); - - agg1.update(1); - agg2.update(2); - - agg1.merge(agg2); - - // Verify that the values did NOT merge - auto value_set = agg1.get_values(); - ASSERT_EQ(value_set[0], 1); // min - ASSERT_EQ(value_set[0], 1); // max - ASSERT_EQ(value_set[0], 1); // sum - ASSERT_EQ(value_set[0], 1); // count -} - -TEST(MinMaxSumCountAggregator, Types) -{ - // This test verifies that we do not encounter any errors when - // using various numeric types. - MinMaxSumCountAggregator agg_int(opentelemetry::metrics::InstrumentKind::Counter); - MinMaxSumCountAggregator agg_long(opentelemetry::metrics::InstrumentKind::Counter); - MinMaxSumCountAggregator agg_float(opentelemetry::metrics::InstrumentKind::Counter); - MinMaxSumCountAggregator agg_double(opentelemetry::metrics::InstrumentKind::Counter); - - for (int i = 1; i <= 10; ++i) - { - agg_int.update(i); - agg_long.update(i); - } - - for (float i = 1.0; i <= 10.0; i += 1) - { - agg_float.update(i); - agg_double.update(i); - } - - auto value_set = agg_int.get_values(); - ASSERT_EQ(value_set[0], 1); // min - ASSERT_EQ(value_set[1], 10); // max - ASSERT_EQ(value_set[2], 55); // sum - ASSERT_EQ(value_set[3], 10); // count - - auto value_set2 = agg_long.get_values(); - ASSERT_EQ(value_set[0], 1); // min - ASSERT_EQ(value_set[1], 10); // max - ASSERT_EQ(value_set[2], 55); // sum - ASSERT_EQ(value_set[3], 10); // count - - auto value_set3 = agg_float.get_values(); - ASSERT_EQ(value_set[0], 1.0); // min - ASSERT_EQ(value_set[1], 10.0); // max - ASSERT_EQ(value_set[2], 55.0); // sum - ASSERT_EQ(value_set[3], 10); // count - - auto value_set4 = agg_double.get_values(); - ASSERT_EQ(value_set[0], 1.0); // min - ASSERT_EQ(value_set[1], 10.0); // max - ASSERT_EQ(value_set[2], 55.0); // sum - ASSERT_EQ(value_set[3], 10); // count -} - -static void callback(MinMaxSumCountAggregator &agg) -{ - // 1 + 2 + ... + 10000 = 50005000 - for (int i = 1; i <= 10000; ++i) - { - agg.update(i); - } -} - -TEST(MinMaxSumCountAggregator, Concurrency) -{ - // This test checks that the aggregator updates appropriately - // when called in a multi-threaded context. - MinMaxSumCountAggregator agg(opentelemetry::metrics::InstrumentKind::Counter); - - std::thread first(&callback, std::ref(agg)); - std::thread second(&callback, std::ref(agg)); - - first.join(); - second.join(); - - auto value_set = agg.get_values(); - ASSERT_EQ(value_set[0], 1); - ASSERT_EQ(value_set[1], 10000); - ASSERT_EQ(value_set[2], 2 * 50005000); - ASSERT_EQ(value_set[3], 2 * 10000); -} \ No newline at end of file diff --git a/sdk/test/trace/always_off_sampler_test.cc b/sdk/test/trace/always_off_sampler_test.cc index ce2f11c5b7..2c892fcfa7 100644 --- a/sdk/test/trace/always_off_sampler_test.cc +++ b/sdk/test/trace/always_off_sampler_test.cc @@ -7,24 +7,24 @@ using opentelemetry::sdk::trace::Decision; TEST(AlwaysOffSampler, ShouldSample) { - AlwaysOffSampler sampler; + AlwaysOffSampler sampler; - opentelemetry::trace::TraceId trace_id; - opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; + opentelemetry::trace::TraceId trace_id; + opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; - using M = std::map; - M m1 = {{}}; - opentelemetry::trace::KeyValueIterableView view{m1}; + using M = std::map; + M m1 = {{}}; + opentelemetry::trace::KeyValueIterableView view{m1}; - auto sampling_result = sampler.ShouldSample(nullptr, trace_id, "", span_kind, view); + auto sampling_result = sampler.ShouldSample(nullptr, trace_id, "", span_kind, view); - ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); - ASSERT_EQ(nullptr, sampling_result.attributes); + ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); + ASSERT_EQ(nullptr, sampling_result.attributes); } TEST(AlwaysOffSampler, GetDescription) { - AlwaysOffSampler sampler; + AlwaysOffSampler sampler; - ASSERT_EQ("AlwaysOffSampler", sampler.GetDescription()); + ASSERT_EQ("AlwaysOffSampler", sampler.GetDescription()); } diff --git a/sdk/test/trace/parent_or_else_sampler_test.cc b/sdk/test/trace/parent_or_else_sampler_test.cc index 311ffae59f..93ce56dfb1 100644 --- a/sdk/test/trace/parent_or_else_sampler_test.cc +++ b/sdk/test/trace/parent_or_else_sampler_test.cc @@ -18,14 +18,14 @@ TEST(ParentOrElseSampler, ShouldSample) // Set up parameters opentelemetry::trace::TraceId trace_id; opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; - using M = std::map; - M m1 = {{}}; + using M = std::map; + M m1 = {{}}; opentelemetry::trace::KeyValueIterableView view{m1}; SpanContext parent_context_sampled(true, false); SpanContext parent_context_nonsampled(false, false); // Case 1: Parent doesn't exist. Return result of delegateSampler() - auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view); + auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view); auto sampling_result2 = sampler_on.ShouldSample(nullptr, trace_id, "", span_kind, view); ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); diff --git a/sdk/test/trace/probability_sampler_test.cc b/sdk/test/trace/probability_sampler_test.cc index 75a11a1fc7..37e2a6c943 100644 --- a/sdk/test/trace/probability_sampler_test.cc +++ b/sdk/test/trace/probability_sampler_test.cc @@ -24,7 +24,9 @@ namespace * generate a random trace_id and check if it should sample using the provided * provider and context */ -int RunShouldSampleCountDecision(SpanContext &context, ProbabilitySampler &sampler, int iterations) +int RunShouldSampleCountDecision(SpanContext &context, + ProbabilitySampler &sampler, + int iterations) { int actual_count = 0; diff --git a/tools/format.sh b/tools/format.sh index 7d5249d5e3..1b150dbca3 100755 --- a/tools/format.sh +++ b/tools/format.sh @@ -16,9 +16,8 @@ fi # Correct common miscapitalizations. "${SED[@]}" 's/Open[t]elemetry/OpenTelemetry/g' $($FIND -type f -print) -# No CRLF line endings, except Windows files. -"${SED[@]}" 's/\r$//' $($FIND -name '*.ps1' -prune -o \ - -name '*.cmd' -prune -o -type f -print) +# No CRLF line endings. +"${SED[@]}" 's/\r$//' $($FIND -type f -print) # No trailing spaces. "${SED[@]}" 's/ \+$//' $($FIND -type f -print) From 1a99330854b5724c5581d9b22dfde6e682d82ae9 Mon Sep 17 00:00:00 2001 From: Keshav Manghat Date: Tue, 4 Aug 2020 16:29:16 +0000 Subject: [PATCH 37/37] Updated zpages example --- examples/zpages/zpages_example.cc | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/zpages/zpages_example.cc b/examples/zpages/zpages_example.cc index fb3ad5fbd3..2d6d36c37f 100644 --- a/examples/zpages/zpages_example.cc +++ b/examples/zpages/zpages_example.cc @@ -22,17 +22,23 @@ int main(int argc, char* argv[]) { std::cout << "This example for zPages creates a few types of spans and then " << "creates a span every second for the duration of the application" << "\n"; - // Create a span of each type(running, completed and error) - auto running_span = tracer->StartSpan("examplespan1"); - running_span->SetAttribute("attribute1", 314159); - running_span->End(); - tracer->StartSpan("examplespan")->End(); - tracer->StartSpan("examplespan")->SetStatus( + // Create a map of attributes for the span + int listInt[] = {1, 2, 3}; + std::map attribute_map; + attribute_map["attribute1"] = opentelemetry::nostd::span(listInt); + attribute_map["attribute2"] = 314159; + + // Create a span of each type(running, completed and error) + tracer->StartSpan("examplespan1",attribute_map)->End(); + + tracer->StartSpan("examplespan1")->End(); + tracer->StartSpan("examplespan1")->SetStatus( opentelemetry::trace::CanonicalCode::CANCELLED, "Cancelled example"); // Create another running span with a different name - auto running_span2 = tracer->StartSpan("examplespan2"); + auto running_span = tracer->StartSpan("examplespan2"); + // Create a completed span every second till user stops the loop std::cout << "Presss CTRL+C to stop...\n"; while(true){