Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
80432edbd0 | |||
23606b45c7 | |||
2aac0afca3 | |||
508d8c7253 | |||
8f5134528b | |||
738c6040f7 | |||
1350e9b307 | |||
4e2a40e031 | |||
594d2e194a | |||
977a1ed7e1 | |||
8b3789af56 | |||
f60485d9c2 | |||
b05b124cb3 | |||
723c208f22 | |||
21758f1183 | |||
422febf15d | |||
51ec32405d | |||
6a90dc7259 | |||
262f32857f | |||
91fb3992ac | |||
e8b12feaeb | |||
730fbc5b31 | |||
d0562664ad | |||
d9b4beff8b | |||
b2f21840c6 | |||
67cb48537a | |||
fa0408e70b | |||
032ed9af9c | |||
dc84080401 | |||
82e759732b | |||
61dbcc2b84 | |||
e61680ff0f | |||
6f188a5131 | |||
6077f86af8 | |||
93167e3917 | |||
2526a94454 | |||
97cc543e53 | |||
62d220f49a | |||
49995e32f0 | |||
d525c28907 | |||
39c84c7d51 |
5
.github/workflows/unittest_linux.yml
vendored
5
.github/workflows/unittest_linux.yml
vendored
@ -9,5 +9,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make test_make
|
||||
run: make test_make
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- name: make test
|
||||
run: make test
|
||||
|
14
.github/workflows/unittest_linux_asan.yml
vendored
Normal file
14
.github/workflows/unittest_linux_asan.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: linux_asan
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- name: make test_asan
|
||||
run: make test_asan
|
@ -9,6 +9,7 @@ jobs:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- name: install mbedtls
|
||||
run: brew install mbedtls
|
||||
- name: make test
|
||||
|
@ -9,6 +9,7 @@ jobs:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- name: install openssl
|
||||
run: brew install openssl@1.1
|
||||
- name: make test
|
||||
|
@ -9,5 +9,6 @@ jobs:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make test_tsan
|
||||
run: make test_tsan
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- name: make test_tsan_sectransport
|
||||
run: make test_tsan_sectransport
|
||||
|
19
CMake/FindDeflate.cmake
Normal file
19
CMake/FindDeflate.cmake
Normal file
@ -0,0 +1,19 @@
|
||||
# Find package structure taken from libcurl
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(DEFLATE_INCLUDE_DIRS libdeflate.h)
|
||||
find_library(DEFLATE_LIBRARY deflate)
|
||||
|
||||
find_package_handle_standard_args(Deflate
|
||||
FOUND_VAR
|
||||
DEFLATE_FOUND
|
||||
REQUIRED_VARS
|
||||
DEFLATE_LIBRARY
|
||||
DEFLATE_INCLUDE_DIRS
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find deflate"
|
||||
)
|
||||
|
||||
set(DEFLATE_INCLUDE_DIRS ${DEFLATE_INCLUDE_DIRS})
|
||||
set(DEFLATE_LIBRARIES ${DEFLATE_LIBRARY})
|
@ -8,7 +8,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
|
||||
|
||||
project(ixwebsocket C CXX)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
set (CXX_STANDARD_REQUIRED ON)
|
||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
@ -31,6 +31,7 @@ set( IXWEBSOCKET_SOURCES
|
||||
ixwebsocket/IXDNSLookup.cpp
|
||||
ixwebsocket/IXExponentialBackoff.cpp
|
||||
ixwebsocket/IXGetFreePort.cpp
|
||||
ixwebsocket/IXGzipCodec.cpp
|
||||
ixwebsocket/IXHttp.cpp
|
||||
ixwebsocket/IXHttpClient.cpp
|
||||
ixwebsocket/IXHttpServer.cpp
|
||||
@ -44,6 +45,7 @@ set( IXWEBSOCKET_SOURCES
|
||||
ixwebsocket/IXSocketFactory.cpp
|
||||
ixwebsocket/IXSocketServer.cpp
|
||||
ixwebsocket/IXSocketTLSOptions.cpp
|
||||
ixwebsocket/IXStrCaseCompare.cpp
|
||||
ixwebsocket/IXUdpSocket.cpp
|
||||
ixwebsocket/IXUrlParser.cpp
|
||||
ixwebsocket/IXUserAgent.cpp
|
||||
@ -66,6 +68,7 @@ set( IXWEBSOCKET_HEADERS
|
||||
ixwebsocket/IXDNSLookup.h
|
||||
ixwebsocket/IXExponentialBackoff.h
|
||||
ixwebsocket/IXGetFreePort.h
|
||||
ixwebsocket/IXGzipCodec.h
|
||||
ixwebsocket/IXHttp.h
|
||||
ixwebsocket/IXHttpClient.h
|
||||
ixwebsocket/IXHttpServer.h
|
||||
@ -80,6 +83,7 @@ set( IXWEBSOCKET_HEADERS
|
||||
ixwebsocket/IXSocketFactory.h
|
||||
ixwebsocket/IXSocketServer.h
|
||||
ixwebsocket/IXSocketTLSOptions.h
|
||||
ixwebsocket/IXStrCaseCompare.h
|
||||
ixwebsocket/IXUdpSocket.h
|
||||
ixwebsocket/IXUrlParser.h
|
||||
ixwebsocket/IXUtf8Validator.h
|
||||
@ -200,6 +204,14 @@ if (USE_ZLIB)
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_ZLIB)
|
||||
endif()
|
||||
|
||||
# brew install libdeflate
|
||||
find_package(Deflate)
|
||||
if (DEFLATE_FOUND)
|
||||
include_directories(${DEFLATE_INCLUDE_DIRS})
|
||||
target_link_libraries(ixwebsocket ${DEFLATE_LIBRARIES})
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_DEFLATE)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
@ -251,12 +263,19 @@ if (USE_WS OR USE_TEST)
|
||||
add_subdirectory(ixsentry)
|
||||
add_subdirectory(ixbots)
|
||||
|
||||
add_subdirectory(third_party/spdlog spdlog)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(spdlog
|
||||
GIT_REPOSITORY "https://github.com/gabime/spdlog"
|
||||
GIT_TAG "v1.8.0"
|
||||
GIT_SHALLOW 1)
|
||||
|
||||
FetchContent_MakeAvailable(spdlog)
|
||||
|
||||
if (USE_WS)
|
||||
add_subdirectory(ws)
|
||||
add_subdirectory(ws)
|
||||
endif()
|
||||
if (USE_TEST)
|
||||
add_subdirectory(test)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
endif()
|
||||
|
19
README.md
19
README.md
@ -4,6 +4,8 @@ IXWebSocket is a C++ library for WebSocket client and server development. It has
|
||||
|
||||
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Note that the MinGW compiler is not supported at this point. Two important design goals are simplicity and correctness.
|
||||
|
||||
A bad security bug affecting users compiling with SSL enabled and OpenSSL as the backend was just fixed in newly released version 11.0.0. Please upgrade ! (more details in the [https://github.com/machinezone/IXWebSocket/pull/250](PR).
|
||||
|
||||
```cpp
|
||||
/*
|
||||
* main.cpp
|
||||
@ -84,23 +86,26 @@ If your company or project is using this library, feel free to open an issue or
|
||||
- [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), an easy to use Discord-bot framework.
|
||||
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
|
||||
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
|
||||
- [discord.cpp](https://github.com/luccanunes/discord.cpp), a discord library for making bots
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
| OS | TLS | Sanitizer | Status |
|
||||
|-------------------|-------------------|-------------------|-------------------|
|
||||
| Linux | OpenSSL | None | [![Build2][1]][7] |
|
||||
| macOS | Secure Transport | Thread Sanitizer | [![Build2][2]][7] |
|
||||
| macOS | OpenSSL | Thread Sanitizer | [![Build2][3]][7] |
|
||||
| macOS | MbedTLS | Thread Sanitizer | [![Build2][4]][7] |
|
||||
| Windows | Disabled | None | [![Build2][5]][7] |
|
||||
| UWP | Disabled | None | [![Build2][6]][7] |
|
||||
| Linux | OpenSSL | None | [![Build2][1]][0] |
|
||||
| macOS | Secure Transport | Thread Sanitizer | [![Build2][2]][0] |
|
||||
| macOS | OpenSSL | Thread Sanitizer | [![Build2][3]][0] |
|
||||
| macOS | MbedTLS | Thread Sanitizer | [![Build2][4]][0] |
|
||||
| Windows | Disabled | None | [![Build2][5]][0] |
|
||||
| UWP | Disabled | None | [![Build2][6]][0] |
|
||||
| Linux | OpenSSL | Address Sanitizer | [![Build2][7]][0] |
|
||||
|
||||
[0]: https://github.com/machinezone/IXWebSocket
|
||||
[1]: https://github.com/machinezone/IXWebSocket/workflows/linux/badge.svg
|
||||
[2]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_sectransport/badge.svg
|
||||
[3]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_openssl/badge.svg
|
||||
[4]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_mbedtls/badge.svg
|
||||
[5]: https://github.com/machinezone/IXWebSocket/workflows/windows/badge.svg
|
||||
[6]: https://github.com/machinezone/IXWebSocket/workflows/uwp/badge.svg
|
||||
[7]: https://github.com/machinezone/IXWebSocket
|
||||
[7]: https://github.com/machinezone/IXWebSocket/workflows/linux_asan/badge.svg
|
||||
|
||||
|
@ -2,7 +2,7 @@ FROM alpine:3.12 as build
|
||||
|
||||
RUN apk add --no-cache \
|
||||
gcc g++ musl-dev linux-headers \
|
||||
cmake mbedtls-dev make zlib-dev python3-dev ninja
|
||||
cmake mbedtls-dev make zlib-dev python3-dev ninja git
|
||||
|
||||
RUN addgroup -S app && \
|
||||
adduser -S -G app app && \
|
||||
|
26
docker/Dockerfile.centos7
Normal file
26
docker/Dockerfile.centos7
Normal file
@ -0,0 +1,26 @@
|
||||
FROM centos:7 as build
|
||||
|
||||
RUN yum install -y gcc-c++ make zlib-devel openssl-devel redhat-rpm-config
|
||||
|
||||
RUN groupadd app && useradd -g app app
|
||||
RUN chown -R app:app /opt
|
||||
RUN chown -R app:app /usr/local
|
||||
|
||||
WORKDIR /tmp
|
||||
RUN curl -O https://cmake.org/files/v3.14/cmake-3.14.0-Linux-x86_64.tar.gz
|
||||
RUN tar zxvf cmake-3.14.0-Linux-x86_64.tar.gz
|
||||
RUN cp -rf cmake-3.14.0-Linux-x86_64/* /usr/
|
||||
|
||||
RUN yum install -y git
|
||||
|
||||
# There is a bug in CMake where we cannot build from the root top folder
|
||||
# So we build from /opt
|
||||
COPY --chown=app:app . /opt
|
||||
WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_no_python" ]
|
||||
RUN [ "rm", "-rf", "build" ]
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
CMD ["--help"]
|
27
docker/Dockerfile.ubuntu_precise
Normal file
27
docker/Dockerfile.ubuntu_precise
Normal file
@ -0,0 +1,27 @@
|
||||
# Build time
|
||||
FROM ubuntu:precise as build
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install wget
|
||||
RUN mkdir -p /tmp/cmake
|
||||
WORKDIR /tmp/cmake
|
||||
RUN wget --no-check-certificate https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0-Linux-x86_64.tar.gz
|
||||
RUN tar zxf cmake-3.14.0-Linux-x86_64.tar.gz
|
||||
|
||||
RUN apt-get -y install g++
|
||||
RUN apt-get -y install libssl-dev
|
||||
RUN apt-get -y install libz-dev
|
||||
RUN apt-get -y install make
|
||||
RUN apt-get -y install python
|
||||
RUN apt-get -y install git
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG CMAKE_BIN_PATH=/tmp/cmake/cmake-3.14.0-Linux-x86_64/bin
|
||||
ENV PATH="${CMAKE_BIN_PATH}:${PATH}"
|
||||
|
||||
RUN ["make", "ws_no_python"]
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
CMD ["--help"]
|
22
docker/Dockerfile.ubuntu_trusty
Normal file
22
docker/Dockerfile.ubuntu_trusty
Normal file
@ -0,0 +1,22 @@
|
||||
# Build time
|
||||
FROM ubuntu:trusty as build
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install wget
|
||||
RUN mkdir -p /tmp/cmake
|
||||
WORKDIR /tmp/cmake
|
||||
RUN wget --no-check-certificate https://github.com/Kitware/CMake/releases/download/v3.14.0/cmake-3.14.0-Linux-x86_64.tar.gz
|
||||
RUN tar zxf cmake-3.14.0-Linux-x86_64.tar.gz
|
||||
|
||||
RUN apt-get -y install g++ libssl-dev libz-dev make python git
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG CMAKE_BIN_PATH=/tmp/cmake/cmake-3.14.0-Linux-x86_64/bin
|
||||
ENV PATH="${CMAKE_BIN_PATH}:${PATH}"
|
||||
|
||||
RUN ["make", "ws_no_python"]
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
CMD ["--help"]
|
@ -2,6 +2,86 @@
|
||||
|
||||
All changes to this project will be documented in this file.
|
||||
|
||||
## [11.0.2] - 2020-11-15
|
||||
|
||||
(ixwebsocket) use a C++11 compatible make_unique shim
|
||||
|
||||
## [11.0.1] - 2020-11-11
|
||||
|
||||
(socket) replace a std::vector with an std::array used as a tmp buffer in Socket::readBytes
|
||||
|
||||
## [11.0.0] - 2020-11-11
|
||||
|
||||
(openssl security fix) in the client to server connection, peer verification is not done in all cases. See https://github.com/machinezone/IXWebSocket/pull/250
|
||||
|
||||
## [10.5.7] - 2020-11-07
|
||||
|
||||
(docker) build docker container with zlib disabled
|
||||
|
||||
## [10.5.6] - 2020-11-07
|
||||
|
||||
(cmake) DEFLATE -> Deflate in CMake to stop warnings about casing
|
||||
|
||||
## [10.5.5] - 2020-11-07
|
||||
|
||||
(ws autoroute) Display result in compliant way (AUTOROUTE IXWebSocket :: N ms) so that result can be parsed easily
|
||||
|
||||
## [10.5.4] - 2020-10-30
|
||||
|
||||
(ws gunzip + IXGZipCodec) Can decompress gziped data with libdeflate. ws gunzip computed output filename was incorrect (was the extension aka gz) instead of the file without the extension. Also check whether the output file is writeable.
|
||||
|
||||
## [10.5.3] - 2020-10-19
|
||||
|
||||
(http code) With zlib disabled, some code should not be reached
|
||||
|
||||
## [10.5.2] - 2020-10-12
|
||||
|
||||
(ws curl) Add support for --data-binary option, to set the request body. When present the request will be sent with the POST verb
|
||||
|
||||
## [10.5.1] - 2020-10-09
|
||||
|
||||
(http client + server + ws) Add support for compressing http client requests with gzip. --compress_request argument is used in ws to enable this. The Content-Encoding is set to gzip, and decoded on the server side if present.
|
||||
|
||||
## [10.5.0] - 2020-09-30
|
||||
|
||||
(http client + server + ws) Add support for uploading files with ws -F foo=@filename, new -D http server option to debug incoming client requests, internal api changed for http POST, PUT and PATCH to supply an HttpFormDataParameters
|
||||
|
||||
## [10.4.9] - 2020-09-30
|
||||
|
||||
(http server + utility code) Add support for doing gzip compression with libdeflate library, if available
|
||||
|
||||
## [10.4.8] - 2020-09-30
|
||||
|
||||
(cmake) Stop using FetchContent cmake module to retrieve jsoncpp third party dependency
|
||||
|
||||
## [10.4.7] - 2020-09-28
|
||||
|
||||
(ws) add gzip and gunzip ws sub commands
|
||||
|
||||
## [10.4.6] - 2020-09-26
|
||||
|
||||
(cmake) use FetchContent cmake module to retrieve jsoncpp third party dependency
|
||||
|
||||
## [10.4.5] - 2020-09-26
|
||||
|
||||
(cmake) use FetchContent cmake module to retrieve spdlog third party dependency
|
||||
|
||||
## [10.4.4] - 2020-09-22
|
||||
|
||||
(cobra connection) retrieve cobra server connection id from the cobra handshake message and display it in ws clients, metrics publisher and bots
|
||||
|
||||
## [10.4.3] - 2020-09-22
|
||||
|
||||
(cobra 2 cobra) specify as an HTTP header which channel we will republish to
|
||||
|
||||
## [10.4.2] - 2020-09-18
|
||||
|
||||
(cobra bots) change an error log to a warning log when reconnecting because no messages were received for a minute
|
||||
|
||||
## [10.4.1] - 2020-09-18
|
||||
|
||||
(cobra connection and bots) set an HTTP header when connecting to help with debugging bots
|
||||
|
||||
## [10.4.0] - 2020-09-12
|
||||
|
||||
(http server) read body request when the Content-Length is specified + set timeout to read the request to 30 seconds max by default, and make it configurable as a constructor parameter
|
||||
|
@ -458,18 +458,25 @@ out = httpClient.get(url, args);
|
||||
// POST request with parameters
|
||||
HttpParameters httpParameters;
|
||||
httpParameters["foo"] = "bar";
|
||||
out = httpClient.post(url, httpParameters, args);
|
||||
|
||||
// HTTP form data can be passed in as well, for multi-part upload of files
|
||||
HttpFormDataParameters httpFormDataParameters;
|
||||
httpParameters["baz"] = "booz";
|
||||
|
||||
out = httpClient.post(url, httpParameters, httpFormDataParameters, args);
|
||||
|
||||
// POST request with a body
|
||||
out = httpClient.post(url, std::string("foo=bar"), args);
|
||||
|
||||
// PUT and PATCH are available too.
|
||||
|
||||
//
|
||||
// Result
|
||||
//
|
||||
auto statusCode = response->statusCode; // Can be HttpErrorCode::Ok, HttpErrorCode::UrlMalformed, etc...
|
||||
auto errorCode = response->errorCode; // 200, 404, etc...
|
||||
auto responseHeaders = response->headers; // All the headers in a special case-insensitive unordered_map of (string, string)
|
||||
auto payload = response->payload; // All the bytes from the response as an std::string
|
||||
auto body = response->body; // All the bytes from the response as an std::string
|
||||
auto errorMsg = response->errorMsg; // Descriptive error message in case of failure
|
||||
auto uploadSize = response->uploadSize; // Byte count of uploaded data
|
||||
auto downloadSize = response->downloadSize; // Byte count of downloaded data
|
||||
|
@ -31,6 +31,8 @@ namespace ix
|
||||
auto limitReceivedEvents = botConfig.limitReceivedEvents;
|
||||
auto batchSize = botConfig.batchSize;
|
||||
|
||||
config.headers["X-Cobra-Channel"] = channel;
|
||||
|
||||
ix::CobraConnection conn;
|
||||
conn.configure(config);
|
||||
conn.connect();
|
||||
@ -128,7 +130,7 @@ namespace ix
|
||||
ss << "no messages received or sent for "
|
||||
<< heartBeatTimeout << " seconds, reconnecting";
|
||||
|
||||
CoreLogger::error(ss.str());
|
||||
CoreLogger::warn(ss.str());
|
||||
stalledConnection = true;
|
||||
}
|
||||
state = currentState;
|
||||
@ -168,7 +170,11 @@ namespace ix
|
||||
}
|
||||
else if (event->type == ix::CobraEventType::Closed)
|
||||
{
|
||||
CoreLogger::info("Subscriber closed: {}" + event->errMsg);
|
||||
CoreLogger::info("Subscriber closed: " + event->errMsg);
|
||||
}
|
||||
else if (event->type == ix::CobraEventType::Handshake)
|
||||
{
|
||||
CoreLogger::info("Subscriber: Cobra handshake connection id: " + event->connectionId);
|
||||
}
|
||||
else if (event->type == ix::CobraEventType::Authenticated)
|
||||
{
|
||||
|
@ -23,6 +23,8 @@ namespace ix
|
||||
CobraConfig cobraPublisherConfig = cobraBotConfig.cobraConfig;
|
||||
cobraPublisherConfig.rolename = publisherRolename;
|
||||
cobraPublisherConfig.rolesecret = publisherRolesecret;
|
||||
cobraPublisherConfig.headers["X-Cobra-Republish-Channel"] = republishChannel;
|
||||
|
||||
cobraMetricsPublisher.configure(cobraPublisherConfig, republishChannel);
|
||||
|
||||
bot.setOnBotMessageCallback(
|
||||
|
@ -41,7 +41,7 @@ namespace ix
|
||||
else
|
||||
{
|
||||
CoreLogger::error("Error sending data to sentry: " + std::to_string(response->statusCode));
|
||||
CoreLogger::error("Response: " + response->payload);
|
||||
CoreLogger::error("Response: " + response->body);
|
||||
|
||||
// Error 429 Too Many Requests
|
||||
if (response->statusCode == 429)
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
#include <ixwebsocket/IXWebSocketPerMessageDeflateOptions.h>
|
||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
@ -19,6 +20,7 @@ namespace ix
|
||||
std::string rolesecret;
|
||||
WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions;
|
||||
SocketTLSOptions socketTLSOptions;
|
||||
WebSocketHttpHeaders headers;
|
||||
|
||||
CobraConfig(const std::string& a = std::string(),
|
||||
const std::string& e = std::string(),
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <ixcrypto/IXHMac.h>
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <ixwebsocket/IXUniquePtr.h>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
@ -91,13 +92,14 @@ namespace ix
|
||||
const std::string& errorMsg,
|
||||
const WebSocketHttpHeaders& headers,
|
||||
const std::string& subscriptionId,
|
||||
CobraConnection::MsgId msgId)
|
||||
CobraConnection::MsgId msgId,
|
||||
const std::string& connectionId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_eventCallbackMutex);
|
||||
if (_eventCallback)
|
||||
{
|
||||
_eventCallback(
|
||||
std::make_unique<CobraEvent>(eventType, errorMsg, headers, subscriptionId, msgId));
|
||||
ix::make_unique<CobraEvent>(eventType, errorMsg, headers, subscriptionId, msgId, connectionId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,7 +257,8 @@ namespace ix
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
const WebSocketPerMessageDeflateOptions& webSocketPerMessageDeflateOptions,
|
||||
const SocketTLSOptions& socketTLSOptions)
|
||||
const SocketTLSOptions& socketTLSOptions,
|
||||
const WebSocketHttpHeaders& headers)
|
||||
{
|
||||
_roleName = rolename;
|
||||
_roleSecret = rolesecret;
|
||||
@ -269,6 +272,7 @@ namespace ix
|
||||
_webSocket->setUrl(url);
|
||||
_webSocket->setPerMessageDeflateOptions(webSocketPerMessageDeflateOptions);
|
||||
_webSocket->setTLSOptions(socketTLSOptions);
|
||||
_webSocket->setExtraHeaders(headers);
|
||||
|
||||
// Send a websocket ping every N seconds (N = 30) now
|
||||
// This should keep the connection open and prevent some load balancers such as
|
||||
@ -283,7 +287,8 @@ namespace ix
|
||||
config.rolename,
|
||||
config.rolesecret,
|
||||
config.webSocketPerMessageDeflateOptions,
|
||||
config.socketTLSOptions);
|
||||
config.socketTLSOptions,
|
||||
config.headers);
|
||||
}
|
||||
|
||||
//
|
||||
@ -349,6 +354,18 @@ namespace ix
|
||||
|
||||
if (!nonce.isString()) return false;
|
||||
|
||||
if (!data.isMember("connection_id")) return false;
|
||||
Json::Value connectionId = data["connection_id"];
|
||||
|
||||
if (!connectionId.isString()) return false;
|
||||
|
||||
invokeEventCallback(ix::CobraEventType::Handshake,
|
||||
std::string(),
|
||||
WebSocketHttpHeaders(),
|
||||
std::string(),
|
||||
0,
|
||||
connectionId.asString());
|
||||
|
||||
return sendAuthMessage(nonce.asString());
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,8 @@ namespace ix
|
||||
const std::string& rolename,
|
||||
const std::string& rolesecret,
|
||||
const WebSocketPerMessageDeflateOptions& webSocketPerMessageDeflateOptions,
|
||||
const SocketTLSOptions& socketTLSOptions);
|
||||
const SocketTLSOptions& socketTLSOptions,
|
||||
const WebSocketHttpHeaders& headers);
|
||||
|
||||
void configure(const ix::CobraConfig& config);
|
||||
|
||||
@ -157,7 +158,9 @@ namespace ix
|
||||
const std::string& errorMsg = std::string(),
|
||||
const WebSocketHttpHeaders& headers = WebSocketHttpHeaders(),
|
||||
const std::string& subscriptionId = std::string(),
|
||||
uint64_t msgId = std::numeric_limits<uint64_t>::max());
|
||||
uint64_t msgId = std::numeric_limits<uint64_t>::max(),
|
||||
const std::string& connectionId = std::string());
|
||||
|
||||
void invokeErrorCallback(const std::string& errorMsg, const std::string& serializedPdu);
|
||||
|
||||
/// Tells whether the internal queue is empty or not
|
||||
|
@ -21,17 +21,20 @@ namespace ix
|
||||
const ix::WebSocketHttpHeaders& headers;
|
||||
const std::string& subscriptionId;
|
||||
uint64_t msgId; // CobraConnection::MsgId
|
||||
const std::string& connectionId;
|
||||
|
||||
CobraEvent(ix::CobraEventType t,
|
||||
const std::string& e,
|
||||
const ix::WebSocketHttpHeaders& h,
|
||||
const std::string& s,
|
||||
uint64_t m)
|
||||
uint64_t m,
|
||||
const std::string& c)
|
||||
: type(t)
|
||||
, errMsg(e)
|
||||
, headers(h)
|
||||
, subscriptionId(s)
|
||||
, msgId(m)
|
||||
, connectionId(c)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ namespace ix
|
||||
Pong = 7,
|
||||
HandshakeError = 8,
|
||||
AuthenticationError = 9,
|
||||
SubscriptionError = 10
|
||||
SubscriptionError = 10,
|
||||
Handshake = 11
|
||||
};
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ namespace ix
|
||||
ss << it.first << ": " << it.second << std::endl;
|
||||
}
|
||||
}
|
||||
else if (event->type == ix::CobraEventType::Handshake)
|
||||
{
|
||||
ss << "Cobra handshake connection id: " << event->connectionId;
|
||||
}
|
||||
else if (event->type == ix::CobraEventType::Authenticated)
|
||||
{
|
||||
ss << "Authenticated";
|
||||
|
@ -19,4 +19,16 @@ namespace ix
|
||||
|
||||
return hashAddress;
|
||||
}
|
||||
|
||||
uint64_t djb2HashStr(const std::string& data)
|
||||
{
|
||||
uint64_t hashAddress = 5381;
|
||||
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
hashAddress = ((hashAddress << 5) + hashAddress) + data[i];
|
||||
}
|
||||
|
||||
return hashAddress;
|
||||
}
|
||||
} // namespace ix
|
||||
|
@ -8,8 +8,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
uint64_t djb2Hash(const std::vector<uint8_t>& data);
|
||||
uint64_t djb2HashStr(const std::string& data);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
|
||||
namespace ix
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility> // pair
|
||||
#include <vector> // pair
|
||||
|
||||
namespace ix
|
||||
{
|
||||
|
@ -2,6 +2,17 @@
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
check_c_source_compiles("#include <regex>
|
||||
int main()
|
||||
{
|
||||
const std::regex dsnRegex;
|
||||
std::smatch group;
|
||||
std::regex_match(std::string(), group, dsnRegex);
|
||||
return 0;
|
||||
}"
|
||||
HAVE_STD_REGEX)
|
||||
|
||||
set (IXSENTRY_SOURCES
|
||||
ixsentry/IXSentryClient.cpp
|
||||
@ -28,3 +39,7 @@ set(IXSENTRY_INCLUDE_DIRS
|
||||
${JSONCPP_INCLUDE_DIRS})
|
||||
|
||||
target_include_directories( ixsentry PUBLIC ${IXSENTRY_INCLUDE_DIRS} )
|
||||
|
||||
if (HAVE_STD_REGEX)
|
||||
target_compile_definitions( ixsentry PUBLIC HAVE_STD_REGEX=1 )
|
||||
endif()
|
||||
|
@ -20,9 +20,12 @@ namespace ix
|
||||
SentryClient::SentryClient(const std::string& dsn)
|
||||
: _dsn(dsn)
|
||||
, _validDsn(false)
|
||||
#ifdef HAVE_STD_REGEX
|
||||
, _luaFrameRegex("\t([^/]+):([0-9]+): in function ['<]([^/]+)['>]")
|
||||
#endif
|
||||
, _httpClient(std::make_shared<HttpClient>(true))
|
||||
{
|
||||
#ifdef HAVE_STD_REGEX
|
||||
const std::regex dsnRegex("(http[s]?)://([^:]+):([^@]+)@([^/]+)/([0-9]+)");
|
||||
std::smatch group;
|
||||
|
||||
@ -38,6 +41,7 @@ namespace ix
|
||||
_publicKey = group.str(2);
|
||||
_secretKey = group.str(3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SentryClient::setTLSOptions(const SocketTLSOptions& tlsOptions)
|
||||
@ -77,6 +81,7 @@ namespace ix
|
||||
{
|
||||
Json::Value frames;
|
||||
|
||||
#ifdef HAVE_STD_REGEX
|
||||
// Split by lines
|
||||
std::string line;
|
||||
std::stringstream tokenStream(stack);
|
||||
@ -107,6 +112,7 @@ namespace ix
|
||||
}
|
||||
|
||||
std::reverse(frames.begin(), frames.end());
|
||||
#endif
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
@ -11,7 +11,9 @@
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
#ifdef HAVE_STD_REGEX
|
||||
#include <regex>
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
{
|
||||
@ -62,7 +64,9 @@ namespace ix
|
||||
|
||||
Json::FastWriter _jsonWriter;
|
||||
|
||||
#ifdef HAVE_STD_REGEX
|
||||
std::regex _luaFrameRegex;
|
||||
#endif
|
||||
|
||||
std::shared_ptr<HttpClient> _httpClient;
|
||||
};
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <ixcore/utils/IXCoreLogger.h>
|
||||
#include <ixcrypto/IXHMac.h>
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <ixwebsocket/IXUniquePtr.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace snake
|
||||
@ -196,7 +197,7 @@ namespace snake
|
||||
{
|
||||
std::string filterStr = pdu["body"]["filter"];
|
||||
}
|
||||
state->streamSql = std::make_unique<StreamSql>(filterStr);
|
||||
state->streamSql = ix::make_unique<StreamSql>(filterStr);
|
||||
state->id = 0;
|
||||
state->onRedisSubscribeCallback = [&ws, state](const std::string& messageStr) {
|
||||
auto msg = nlohmann::json::parse(messageStr);
|
||||
|
@ -33,16 +33,29 @@ namespace ix
|
||||
void Bench::report()
|
||||
{
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start);
|
||||
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now - _start);
|
||||
|
||||
_ms = milliseconds.count();
|
||||
std::cerr << _description << " completed in " << _ms << "ms" << std::endl;
|
||||
_duration = microseconds.count();
|
||||
std::cerr << _description << " completed in " << _duration << " us" << std::endl;
|
||||
|
||||
setReported();
|
||||
}
|
||||
|
||||
void Bench::record()
|
||||
{
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now - _start);
|
||||
|
||||
_duration = microseconds.count();
|
||||
}
|
||||
|
||||
void Bench::setReported()
|
||||
{
|
||||
_reported = true;
|
||||
}
|
||||
|
||||
uint64_t Bench::getDuration() const
|
||||
{
|
||||
return _ms;
|
||||
return _duration;
|
||||
}
|
||||
} // namespace ix
|
||||
|
@ -18,13 +18,15 @@ namespace ix
|
||||
~Bench();
|
||||
|
||||
void reset();
|
||||
void record();
|
||||
void report();
|
||||
void setReported();
|
||||
uint64_t getDuration() const;
|
||||
|
||||
private:
|
||||
std::string _description;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> _start;
|
||||
uint64_t _ms;
|
||||
uint64_t _duration;
|
||||
bool _reported;
|
||||
};
|
||||
} // namespace ix
|
||||
|
@ -68,6 +68,11 @@ namespace ix
|
||||
: resolveUnCancellable(errMsg, isCancellationRequested);
|
||||
}
|
||||
|
||||
void DNSLookup::release(struct addrinfo* addr)
|
||||
{
|
||||
freeaddrinfo(addr);
|
||||
}
|
||||
|
||||
struct addrinfo* DNSLookup::resolveUnCancellable(
|
||||
std::string& errMsg, const CancellationRequest& isCancellationRequested)
|
||||
{
|
||||
|
@ -31,6 +31,8 @@ namespace ix
|
||||
const CancellationRequest& isCancellationRequested,
|
||||
bool cancellable = true);
|
||||
|
||||
void release(struct addrinfo* addr);
|
||||
|
||||
private:
|
||||
struct addrinfo* resolveCancellable(std::string& errMsg,
|
||||
const CancellationRequest& isCancellationRequested);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* IXExponentialBackoff.h
|
||||
* IXExponentialBackoff.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
183
ixwebsocket/IXGzipCodec.cpp
Normal file
183
ixwebsocket/IXGzipCodec.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* IXGzipCodec.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "IXGzipCodec.h"
|
||||
|
||||
#include "IXBench.h"
|
||||
#include <array>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_DEFLATE
|
||||
#include <libdeflate.h>
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
{
|
||||
std::string gzipCompress(const std::string& str)
|
||||
{
|
||||
#ifndef IXWEBSOCKET_USE_ZLIB
|
||||
return std::string();
|
||||
#else
|
||||
#ifdef IXWEBSOCKET_USE_DEFLATE
|
||||
int compressionLevel = 6;
|
||||
struct libdeflate_compressor* compressor;
|
||||
|
||||
compressor = libdeflate_alloc_compressor(compressionLevel);
|
||||
|
||||
const void* uncompressed_data = str.data();
|
||||
size_t uncompressed_size = str.size();
|
||||
void* compressed_data;
|
||||
size_t actual_compressed_size;
|
||||
size_t max_compressed_size;
|
||||
|
||||
max_compressed_size = libdeflate_gzip_compress_bound(compressor, uncompressed_size);
|
||||
compressed_data = malloc(max_compressed_size);
|
||||
|
||||
if (compressed_data == NULL)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
actual_compressed_size = libdeflate_gzip_compress(
|
||||
compressor, uncompressed_data, uncompressed_size, compressed_data, max_compressed_size);
|
||||
|
||||
libdeflate_free_compressor(compressor);
|
||||
|
||||
if (actual_compressed_size == 0)
|
||||
{
|
||||
free(compressed_data);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string out;
|
||||
out.assign(reinterpret_cast<char*>(compressed_data), actual_compressed_size);
|
||||
free(compressed_data);
|
||||
|
||||
return out;
|
||||
#else
|
||||
z_stream zs; // z_stream is zlib's control structure
|
||||
memset(&zs, 0, sizeof(zs));
|
||||
|
||||
// deflateInit2 configure the file format: request gzip instead of deflate
|
||||
const int windowBits = 15;
|
||||
const int GZIP_ENCODING = 16;
|
||||
|
||||
deflateInit2(&zs,
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED,
|
||||
windowBits | GZIP_ENCODING,
|
||||
8,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
|
||||
zs.next_in = (Bytef*) str.data();
|
||||
zs.avail_in = (uInt) str.size(); // set the z_stream's input
|
||||
|
||||
int ret;
|
||||
char outbuffer[32768];
|
||||
std::string outstring;
|
||||
|
||||
// retrieve the compressed bytes blockwise
|
||||
do
|
||||
{
|
||||
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
|
||||
zs.avail_out = sizeof(outbuffer);
|
||||
|
||||
ret = deflate(&zs, Z_FINISH);
|
||||
|
||||
if (outstring.size() < zs.total_out)
|
||||
{
|
||||
// append the block to the output string
|
||||
outstring.append(outbuffer, zs.total_out - outstring.size());
|
||||
}
|
||||
} while (ret == Z_OK);
|
||||
|
||||
deflateEnd(&zs);
|
||||
|
||||
return outstring;
|
||||
#endif // IXWEBSOCKET_USE_DEFLATE
|
||||
#endif // IXWEBSOCKET_USE_ZLIB
|
||||
}
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_DEFLATE
|
||||
static uint32_t loadDecompressedGzipSize(const uint8_t* p)
|
||||
{
|
||||
return ((uint32_t) p[0] << 0) | ((uint32_t) p[1] << 8) | ((uint32_t) p[2] << 16) |
|
||||
((uint32_t) p[3] << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool gzipDecompress(const std::string& in, std::string& out)
|
||||
{
|
||||
#ifndef IXWEBSOCKET_USE_ZLIB
|
||||
return false;
|
||||
#else
|
||||
#ifdef IXWEBSOCKET_USE_DEFLATE
|
||||
struct libdeflate_decompressor* decompressor;
|
||||
decompressor = libdeflate_alloc_decompressor();
|
||||
|
||||
const void* compressed_data = in.data();
|
||||
size_t compressed_size = in.size();
|
||||
|
||||
// Retrieve uncompressed size from the trailer of the gziped data
|
||||
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&in.front());
|
||||
auto uncompressed_size = loadDecompressedGzipSize(&ptr[compressed_size - 4]);
|
||||
|
||||
// Use it to redimension our output buffer
|
||||
out.resize(uncompressed_size);
|
||||
|
||||
libdeflate_result result = libdeflate_gzip_decompress(
|
||||
decompressor, compressed_data, compressed_size, &out.front(), uncompressed_size, NULL);
|
||||
|
||||
libdeflate_free_decompressor(decompressor);
|
||||
return result == LIBDEFLATE_SUCCESS;
|
||||
#else
|
||||
z_stream inflateState;
|
||||
memset(&inflateState, 0, sizeof(inflateState));
|
||||
|
||||
inflateState.zalloc = Z_NULL;
|
||||
inflateState.zfree = Z_NULL;
|
||||
inflateState.opaque = Z_NULL;
|
||||
inflateState.avail_in = 0;
|
||||
inflateState.next_in = Z_NULL;
|
||||
|
||||
if (inflateInit2(&inflateState, 16 + MAX_WBITS) != Z_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inflateState.avail_in = (uInt) in.size();
|
||||
inflateState.next_in = (unsigned char*) (const_cast<char*>(in.data()));
|
||||
|
||||
const int kBufferSize = 1 << 14;
|
||||
std::array<unsigned char, kBufferSize> compressBuffer;
|
||||
|
||||
do
|
||||
{
|
||||
inflateState.avail_out = (uInt) kBufferSize;
|
||||
inflateState.next_out = &compressBuffer.front();
|
||||
|
||||
int ret = inflate(&inflateState, Z_SYNC_FLUSH);
|
||||
|
||||
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
|
||||
{
|
||||
inflateEnd(&inflateState);
|
||||
return false;
|
||||
}
|
||||
|
||||
out.append(reinterpret_cast<char*>(&compressBuffer.front()),
|
||||
kBufferSize - inflateState.avail_out);
|
||||
} while (inflateState.avail_out == 0);
|
||||
|
||||
inflateEnd(&inflateState);
|
||||
return true;
|
||||
#endif // IXWEBSOCKET_USE_DEFLATE
|
||||
#endif // IXWEBSOCKET_USE_ZLIB
|
||||
}
|
||||
} // namespace ix
|
15
ixwebsocket/IXGzipCodec.h
Normal file
15
ixwebsocket/IXGzipCodec.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* IXGzipCodec.h
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
std::string gzipCompress(const std::string& str);
|
||||
bool gzipDecompress(const std::string& in, std::string& out);
|
||||
} // namespace ix
|
@ -7,6 +7,7 @@
|
||||
#include "IXHttp.h"
|
||||
|
||||
#include "IXCancellationRequest.h"
|
||||
#include "IXGzipCodec.h"
|
||||
#include "IXSocket.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
@ -157,6 +158,23 @@ namespace ix
|
||||
body = res.second;
|
||||
}
|
||||
|
||||
// If the content was compressed with gzip, decode it
|
||||
if (headers["Content-Encoding"] == "gzip")
|
||||
{
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
std::string decompressedPayload;
|
||||
if (!gzipDecompress(body, decompressedPayload))
|
||||
{
|
||||
return std::make_tuple(
|
||||
false, std::string("Error during gzip decompression of the body"), httpRequest);
|
||||
}
|
||||
body = decompressedPayload;
|
||||
#else
|
||||
std::string errorMsg("ixwebsocket was not compiled with gzip support on");
|
||||
return std::make_tuple(false, errorMsg, httpRequest);
|
||||
#endif
|
||||
}
|
||||
|
||||
httpRequest = std::make_shared<HttpRequest>(uri, method, httpVersion, body, headers);
|
||||
return std::make_tuple(true, "", httpRequest);
|
||||
}
|
||||
@ -178,7 +196,7 @@ namespace ix
|
||||
|
||||
// Write headers
|
||||
ss.str("");
|
||||
ss << "Content-Length: " << response->payload.size() << "\r\n";
|
||||
ss << "Content-Length: " << response->body.size() << "\r\n";
|
||||
for (auto&& it : response->headers)
|
||||
{
|
||||
ss << it.first << ": " << it.second << "\r\n";
|
||||
@ -190,6 +208,6 @@ namespace ix
|
||||
return false;
|
||||
}
|
||||
|
||||
return response->payload.empty() ? true : socket->writeBytes(response->payload, nullptr);
|
||||
return response->body.empty() ? true : socket->writeBytes(response->body, nullptr);
|
||||
}
|
||||
} // namespace ix
|
||||
|
@ -39,7 +39,7 @@ namespace ix
|
||||
std::string description;
|
||||
HttpErrorCode errorCode;
|
||||
WebSocketHttpHeaders headers;
|
||||
std::string payload;
|
||||
std::string body;
|
||||
std::string errorMsg;
|
||||
uint64_t uploadSize;
|
||||
uint64_t downloadSize;
|
||||
@ -48,7 +48,7 @@ namespace ix
|
||||
const std::string& des = std::string(),
|
||||
const HttpErrorCode& c = HttpErrorCode::Ok,
|
||||
const WebSocketHttpHeaders& h = WebSocketHttpHeaders(),
|
||||
const std::string& p = std::string(),
|
||||
const std::string& b = std::string(),
|
||||
const std::string& e = std::string(),
|
||||
uint64_t u = 0,
|
||||
uint64_t d = 0)
|
||||
@ -56,7 +56,7 @@ namespace ix
|
||||
, description(des)
|
||||
, errorCode(c)
|
||||
, headers(h)
|
||||
, payload(p)
|
||||
, body(b)
|
||||
, errorMsg(e)
|
||||
, uploadSize(u)
|
||||
, downloadSize(d)
|
||||
@ -84,6 +84,7 @@ namespace ix
|
||||
int maxRedirects = 5;
|
||||
bool verbose = false;
|
||||
bool compress = true;
|
||||
bool compressRequest = false;
|
||||
Logger logger;
|
||||
OnProgressCallback onProgressCallback;
|
||||
};
|
||||
|
@ -6,11 +6,11 @@
|
||||
|
||||
#include "IXHttpClient.h"
|
||||
|
||||
#include "IXGzipCodec.h"
|
||||
#include "IXSocketFactory.h"
|
||||
#include "IXUrlParser.h"
|
||||
#include "IXUserAgent.h"
|
||||
#include "IXWebSocketHttpHeaders.h"
|
||||
#include <array>
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
@ -18,10 +18,6 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
{
|
||||
const std::string HttpClient::kPost = "POST";
|
||||
@ -207,6 +203,15 @@ namespace ix
|
||||
|
||||
if (verb == kPost || verb == kPut || verb == kPatch || _forceBody)
|
||||
{
|
||||
// Set request compression header
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
if (args->compressRequest)
|
||||
{
|
||||
ss << "Content-Encoding: gzip"
|
||||
<< "\r\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
ss << "Content-Length: " << body.size() << "\r\n";
|
||||
|
||||
// Set default Content-Type if unspecified
|
||||
@ -501,12 +506,12 @@ namespace ix
|
||||
|
||||
downloadSize = payload.size();
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
// If the content was compressed with gzip, decode it
|
||||
if (headers["Content-Encoding"] == "gzip")
|
||||
{
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
std::string decompressedPayload;
|
||||
if (!gzipInflate(payload, decompressedPayload))
|
||||
if (!gzipDecompress(payload, decompressedPayload))
|
||||
{
|
||||
std::string errorMsg("Error decompressing payload");
|
||||
return std::make_shared<HttpResponse>(code,
|
||||
@ -519,8 +524,18 @@ namespace ix
|
||||
downloadSize);
|
||||
}
|
||||
payload = decompressedPayload;
|
||||
}
|
||||
#else
|
||||
std::string errorMsg("ixwebsocket was not compiled with gzip support on");
|
||||
return std::make_shared<HttpResponse>(code,
|
||||
description,
|
||||
HttpErrorCode::Gzip,
|
||||
headers,
|
||||
payload,
|
||||
errorMsg,
|
||||
uploadSize,
|
||||
downloadSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
return std::make_shared<HttpResponse>(code,
|
||||
description,
|
||||
@ -547,11 +562,42 @@ namespace ix
|
||||
return request(url, kDel, std::string(), args);
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClient::request(const std::string& url,
|
||||
const std::string& verb,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args)
|
||||
{
|
||||
std::string body;
|
||||
|
||||
if (httpFormDataParameters.empty())
|
||||
{
|
||||
body = serializeHttpParameters(httpParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string multipartBoundary = generateMultipartBoundary();
|
||||
args->multipartBoundary = multipartBoundary;
|
||||
body = serializeHttpFormDataParameters(
|
||||
multipartBoundary, httpFormDataParameters, httpParameters);
|
||||
}
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
if (args->compressRequest)
|
||||
{
|
||||
body = gzipCompress(body);
|
||||
}
|
||||
#endif
|
||||
|
||||
return request(url, verb, body, args);
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClient::post(const std::string& url,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args)
|
||||
{
|
||||
return request(url, kPost, serializeHttpParameters(httpParameters), args);
|
||||
return request(url, kPost, httpParameters, httpFormDataParameters, args);
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClient::post(const std::string& url,
|
||||
@ -563,9 +609,10 @@ namespace ix
|
||||
|
||||
HttpResponsePtr HttpClient::put(const std::string& url,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args)
|
||||
{
|
||||
return request(url, kPut, serializeHttpParameters(httpParameters), args);
|
||||
return request(url, kPut, httpParameters, httpFormDataParameters, args);
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClient::put(const std::string& url,
|
||||
@ -577,9 +624,10 @@ namespace ix
|
||||
|
||||
HttpResponsePtr HttpClient::patch(const std::string& url,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args)
|
||||
{
|
||||
return request(url, kPatch, serializeHttpParameters(httpParameters), args);
|
||||
return request(url, kPatch, httpParameters, httpFormDataParameters, args);
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClient::patch(const std::string& url,
|
||||
@ -680,51 +728,6 @@ namespace ix
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
bool HttpClient::gzipInflate(const std::string& in, std::string& out)
|
||||
{
|
||||
z_stream inflateState;
|
||||
std::memset(&inflateState, 0, sizeof(inflateState));
|
||||
|
||||
inflateState.zalloc = Z_NULL;
|
||||
inflateState.zfree = Z_NULL;
|
||||
inflateState.opaque = Z_NULL;
|
||||
inflateState.avail_in = 0;
|
||||
inflateState.next_in = Z_NULL;
|
||||
|
||||
if (inflateInit2(&inflateState, 16 + MAX_WBITS) != Z_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inflateState.avail_in = (uInt) in.size();
|
||||
inflateState.next_in = (unsigned char*) (const_cast<char*>(in.data()));
|
||||
|
||||
const int kBufferSize = 1 << 14;
|
||||
std::array<unsigned char, kBufferSize> compressBuffer;
|
||||
|
||||
do
|
||||
{
|
||||
inflateState.avail_out = (uInt) kBufferSize;
|
||||
inflateState.next_out = &compressBuffer.front();
|
||||
|
||||
int ret = inflate(&inflateState, Z_SYNC_FLUSH);
|
||||
|
||||
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
|
||||
{
|
||||
inflateEnd(&inflateState);
|
||||
return false;
|
||||
}
|
||||
|
||||
out.append(reinterpret_cast<char*>(&compressBuffer.front()),
|
||||
kBufferSize - inflateState.avail_out);
|
||||
} while (inflateState.avail_out == 0);
|
||||
|
||||
inflateEnd(&inflateState);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void HttpClient::log(const std::string& msg, HttpRequestArgsPtr args)
|
||||
{
|
||||
if (args->logger)
|
||||
|
@ -34,6 +34,7 @@ namespace ix
|
||||
|
||||
HttpResponsePtr post(const std::string& url,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args);
|
||||
HttpResponsePtr post(const std::string& url,
|
||||
const std::string& body,
|
||||
@ -41,6 +42,7 @@ namespace ix
|
||||
|
||||
HttpResponsePtr put(const std::string& url,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args);
|
||||
HttpResponsePtr put(const std::string& url,
|
||||
const std::string& body,
|
||||
@ -48,6 +50,7 @@ namespace ix
|
||||
|
||||
HttpResponsePtr patch(const std::string& url,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args);
|
||||
HttpResponsePtr patch(const std::string& url,
|
||||
const std::string& body,
|
||||
@ -58,7 +61,15 @@ namespace ix
|
||||
const std::string& body,
|
||||
HttpRequestArgsPtr args,
|
||||
int redirects = 0);
|
||||
|
||||
HttpResponsePtr request(const std::string& url,
|
||||
const std::string& verb,
|
||||
const HttpParameters& httpParameters,
|
||||
const HttpFormDataParameters& httpFormDataParameters,
|
||||
HttpRequestArgsPtr args);
|
||||
|
||||
void setForceBody(bool value);
|
||||
|
||||
// Async API
|
||||
HttpRequestArgsPtr createRequest(const std::string& url = std::string(),
|
||||
const std::string& verb = HttpClient::kGet);
|
||||
@ -90,10 +101,6 @@ namespace ix
|
||||
private:
|
||||
void log(const std::string& msg, HttpRequestArgsPtr args);
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
bool gzipInflate(const std::string& in, std::string& out);
|
||||
#endif
|
||||
|
||||
// Async API background thread runner
|
||||
void run();
|
||||
// Async API
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "IXHttpServer.h"
|
||||
|
||||
#include "IXGzipCodec.h"
|
||||
#include "IXNetSystem.h"
|
||||
#include "IXSocketConnect.h"
|
||||
#include "IXUserAgent.h"
|
||||
@ -14,10 +15,6 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
std::pair<bool, std::vector<uint8_t>> load(const std::string& path)
|
||||
@ -43,51 +40,6 @@ namespace
|
||||
auto vec = res.second;
|
||||
return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
|
||||
}
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_ZLIB
|
||||
std::string gzipCompress(const std::string& str)
|
||||
{
|
||||
z_stream zs; // z_stream is zlib's control structure
|
||||
memset(&zs, 0, sizeof(zs));
|
||||
|
||||
// deflateInit2 configure the file format: request gzip instead of deflate
|
||||
const int windowBits = 15;
|
||||
const int GZIP_ENCODING = 16;
|
||||
|
||||
deflateInit2(&zs,
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED,
|
||||
windowBits | GZIP_ENCODING,
|
||||
8,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
|
||||
zs.next_in = (Bytef*) str.data();
|
||||
zs.avail_in = (uInt) str.size(); // set the z_stream's input
|
||||
|
||||
int ret;
|
||||
char outbuffer[32768];
|
||||
std::string outstring;
|
||||
|
||||
// retrieve the compressed bytes blockwise
|
||||
do
|
||||
{
|
||||
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
|
||||
zs.avail_out = sizeof(outbuffer);
|
||||
|
||||
ret = deflate(&zs, Z_FINISH);
|
||||
|
||||
if (outstring.size() < zs.total_out)
|
||||
{
|
||||
// append the block to the output string
|
||||
outstring.append(outbuffer, zs.total_out - outstring.size());
|
||||
}
|
||||
} while (ret == Z_OK);
|
||||
|
||||
deflateEnd(&zs);
|
||||
|
||||
return outstring;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
namespace ix
|
||||
@ -238,4 +190,40 @@ namespace ix
|
||||
301, "OK", HttpErrorCode::Ok, headers, std::string());
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Display the client parameter and body on the console
|
||||
//
|
||||
void HttpServer::makeDebugServer()
|
||||
{
|
||||
setOnConnectionCallback(
|
||||
[this](HttpRequestPtr request,
|
||||
std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
|
||||
WebSocketHttpHeaders headers;
|
||||
headers["Server"] = userAgent();
|
||||
|
||||
// Log request
|
||||
std::stringstream ss;
|
||||
ss << connectionState->getRemoteIp() << ":" << connectionState->getRemotePort()
|
||||
<< " " << request->method << " " << request->headers["User-Agent"] << " "
|
||||
<< request->uri;
|
||||
logInfo(ss.str());
|
||||
|
||||
logInfo("== Headers == ");
|
||||
for (auto&& it : request->headers)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << it.first << ": " << it.second;
|
||||
logInfo(oss.str());
|
||||
}
|
||||
logInfo("");
|
||||
|
||||
logInfo("== Body == ");
|
||||
logInfo(request->body);
|
||||
logInfo("");
|
||||
|
||||
return std::make_shared<HttpResponse>(
|
||||
200, "OK", HttpErrorCode::Ok, headers, std::string("OK"));
|
||||
});
|
||||
}
|
||||
} // namespace ix
|
||||
|
@ -38,6 +38,8 @@ namespace ix
|
||||
|
||||
void makeRedirectServer(const std::string& redirectUrl);
|
||||
|
||||
void makeDebugServer();
|
||||
|
||||
private:
|
||||
// Member variables
|
||||
OnConnectionCallback _onConnectionCallback;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "IXSelectInterruptFactory.h"
|
||||
|
||||
#include "IXUniquePtr.h"
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include "IXSelectInterruptPipe.h"
|
||||
#else
|
||||
@ -17,9 +18,9 @@ namespace ix
|
||||
SelectInterruptPtr createSelectInterrupt()
|
||||
{
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
return std::make_unique<SelectInterruptPipe>();
|
||||
return ix::make_unique<SelectInterruptPipe>();
|
||||
#else
|
||||
return std::make_unique<SelectInterrupt>();
|
||||
return ix::make_unique<SelectInterrupt>();
|
||||
#endif
|
||||
}
|
||||
} // namespace ix
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "IXSelectInterruptFactory.h"
|
||||
#include "IXSocketConnect.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
@ -18,6 +19,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
@ -27,7 +29,6 @@ namespace ix
|
||||
{
|
||||
const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default
|
||||
const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout;
|
||||
constexpr size_t Socket::kChunkSize;
|
||||
|
||||
Socket::Socket(int fd)
|
||||
: _sockfd(fd)
|
||||
@ -364,10 +365,7 @@ namespace ix
|
||||
const OnProgressCallback& onProgressCallback,
|
||||
const CancellationRequest& isCancellationRequested)
|
||||
{
|
||||
if (_readBuffer.empty())
|
||||
{
|
||||
_readBuffer.resize(kChunkSize);
|
||||
}
|
||||
std::array<uint8_t, 1 << 14> readBuffer;
|
||||
|
||||
std::vector<uint8_t> output;
|
||||
while (output.size() != length)
|
||||
@ -378,12 +376,12 @@ namespace ix
|
||||
return std::make_pair(false, errorMsg);
|
||||
}
|
||||
|
||||
size_t size = std::min(kChunkSize, length - output.size());
|
||||
ssize_t ret = recv((char*) &_readBuffer[0], size);
|
||||
size_t size = std::min(readBuffer.size(), length - output.size());
|
||||
ssize_t ret = recv((char*) &readBuffer[0], size);
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
output.insert(output.end(), _readBuffer.begin(), _readBuffer.begin() + ret);
|
||||
output.insert(output.end(), readBuffer.begin(), readBuffer.begin() + ret);
|
||||
}
|
||||
else if (ret <= 0 && !Socket::isWaitNeeded())
|
||||
{
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <BaseTsd.h>
|
||||
@ -102,10 +101,6 @@ namespace ix
|
||||
static const int kDefaultPollTimeout;
|
||||
static const int kDefaultPollNoTimeout;
|
||||
|
||||
// Buffer for reading from our socket. That buffer is never resized.
|
||||
std::vector<uint8_t> _readBuffer;
|
||||
static constexpr size_t kChunkSize = 1 << 15;
|
||||
|
||||
SelectInterruptPtr _selectInterrupt;
|
||||
};
|
||||
} // namespace ix
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "IXNetSystem.h"
|
||||
#include "IXSelectInterrupt.h"
|
||||
#include "IXSocket.h"
|
||||
#include "IXUniquePtr.h"
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
@ -65,7 +66,7 @@ namespace ix
|
||||
|
||||
int timeoutMs = 10;
|
||||
bool readyToRead = false;
|
||||
auto selectInterrupt = std::make_unique<SelectInterrupt>();
|
||||
auto selectInterrupt = ix::make_unique<SelectInterrupt>();
|
||||
PollResultType pollResult = Socket::poll(readyToRead, timeoutMs, fd, selectInterrupt);
|
||||
|
||||
if (pollResult == PollResultType::Timeout)
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "IXSocketFactory.h"
|
||||
|
||||
#include "IXUniquePtr.h"
|
||||
#ifdef IXWEBSOCKET_USE_TLS
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_MBED_TLS
|
||||
@ -35,17 +36,17 @@ namespace ix
|
||||
|
||||
if (!tls)
|
||||
{
|
||||
socket = std::make_unique<Socket>(fd);
|
||||
socket = ix::make_unique<Socket>(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef IXWEBSOCKET_USE_TLS
|
||||
#if defined(IXWEBSOCKET_USE_MBED_TLS)
|
||||
socket = std::make_unique<SocketMbedTLS>(tlsOptions, fd);
|
||||
socket = ix::make_unique<SocketMbedTLS>(tlsOptions, fd);
|
||||
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
||||
socket = std::make_unique<SocketOpenSSL>(tlsOptions, fd);
|
||||
socket = ix::make_unique<SocketOpenSSL>(tlsOptions, fd);
|
||||
#elif defined(__APPLE__)
|
||||
socket = std::make_unique<SocketAppleSSL>(tlsOptions, fd);
|
||||
socket = ix::make_unique<SocketAppleSSL>(tlsOptions, fd);
|
||||
#endif
|
||||
#else
|
||||
errorMsg = "TLS support is not enabled on this platform.";
|
||||
|
@ -10,8 +10,10 @@
|
||||
#include "IXSocketOpenSSL.h"
|
||||
|
||||
#include "IXSocketConnect.h"
|
||||
#include "IXUniquePtr.h"
|
||||
#include <cassert>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <Shlwapi.h>
|
||||
#else
|
||||
@ -85,8 +87,7 @@ namespace ix
|
||||
|
||||
std::atomic<bool> SocketOpenSSL::_openSSLInitializationSuccessful(false);
|
||||
std::once_flag SocketOpenSSL::_openSSLInitFlag;
|
||||
std::unique_ptr<std::mutex[]> SocketOpenSSL::_openSSLMutexes =
|
||||
std::make_unique<std::mutex[]>(CRYPTO_num_locks());
|
||||
std::vector<std::unique_ptr<std::mutex>> openSSLMutexes;
|
||||
|
||||
SocketOpenSSL::SocketOpenSSL(const SocketTLSOptions& tlsOptions, int fd)
|
||||
: Socket(fd)
|
||||
@ -111,6 +112,11 @@ namespace ix
|
||||
|
||||
if (CRYPTO_get_locking_callback() == nullptr)
|
||||
{
|
||||
openSSLMutexes.clear();
|
||||
for (int i = 0; i < CRYPTO_num_locks(); ++i)
|
||||
{
|
||||
openSSLMutexes.push_back(ix::make_unique<std::mutex>());
|
||||
}
|
||||
CRYPTO_set_locking_callback(SocketOpenSSL::openSSLLockingCallback);
|
||||
}
|
||||
#endif
|
||||
@ -128,11 +134,11 @@ namespace ix
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
{
|
||||
_openSSLMutexes[type].lock();
|
||||
openSSLMutexes[type]->lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
_openSSLMutexes[type].unlock();
|
||||
openSSLMutexes[type]->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,14 +509,13 @@ namespace ix
|
||||
errMsg += ERR_error_string(sslErr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
SSL_CTX_set_verify(
|
||||
_ssl_context, SSL_VERIFY_PEER, [](int preverify, X509_STORE_CTX*) -> int {
|
||||
return preverify;
|
||||
});
|
||||
SSL_CTX_set_verify_depth(_ssl_context, 4);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_CTX_set_verify(_ssl_context,
|
||||
SSL_VERIFY_PEER,
|
||||
[](int preverify, X509_STORE_CTX*) -> int { return preverify; });
|
||||
SSL_CTX_set_verify_depth(_ssl_context, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -61,7 +61,6 @@ namespace ix
|
||||
|
||||
static std::once_flag _openSSLInitFlag;
|
||||
static std::atomic<bool> _openSSLInitializationSuccessful;
|
||||
static std::unique_ptr<std::mutex[]> _openSSLMutexes;
|
||||
};
|
||||
|
||||
} // namespace ix
|
||||
|
37
ixwebsocket/IXStrCaseCompare.cpp
Normal file
37
ixwebsocket/IXStrCaseCompare.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* IXStrCaseCompare.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2020 Machine Zone. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "IXStrCaseCompare.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char& c1,
|
||||
const unsigned char& c2) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale());
|
||||
#else
|
||||
return std::tolower(c1) < std::tolower(c2);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CaseInsensitiveLess::cmp(const std::string& s1, const std::string& s2)
|
||||
{
|
||||
return std::lexicographical_compare(s1.begin(),
|
||||
s1.end(), // source range
|
||||
s2.begin(),
|
||||
s2.end(), // dest range
|
||||
NocaseCompare()); // comparison
|
||||
}
|
||||
|
||||
bool CaseInsensitiveLess::operator()(const std::string& s1, const std::string& s2) const
|
||||
{
|
||||
return CaseInsensitiveLess::cmp(s1, s2);
|
||||
}
|
||||
} // namespace ix
|
25
ixwebsocket/IXStrCaseCompare.h
Normal file
25
ixwebsocket/IXStrCaseCompare.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* IXStrCaseCompare.h
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2020 Machine Zone. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
struct CaseInsensitiveLess
|
||||
{
|
||||
// Case Insensitive compare_less binary function
|
||||
struct NocaseCompare
|
||||
{
|
||||
bool operator()(const unsigned char& c1, const unsigned char& c2) const;
|
||||
};
|
||||
|
||||
static bool cmp(const std::string& s1, const std::string& s2);
|
||||
|
||||
bool operator()(const std::string& s1, const std::string& s2) const;
|
||||
};
|
||||
} // namespace ix
|
18
ixwebsocket/IXUniquePtr.h
Normal file
18
ixwebsocket/IXUniquePtr.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* IXUniquePtr.h
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
} // namespace ix
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "IXExponentialBackoff.h"
|
||||
#include "IXSetThreadName.h"
|
||||
#include "IXUniquePtr.h"
|
||||
#include "IXUtf8Validator.h"
|
||||
#include "IXWebSocketHandshake.h"
|
||||
#include <cassert>
|
||||
@ -34,12 +35,12 @@ namespace ix
|
||||
_ws.setOnCloseCallback(
|
||||
[this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) {
|
||||
_onMessageCallback(
|
||||
std::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
|
||||
"",
|
||||
wireSize,
|
||||
WebSocketErrorInfo(),
|
||||
WebSocketOpenInfo(),
|
||||
WebSocketCloseInfo(code, reason, remote)));
|
||||
ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
|
||||
"",
|
||||
wireSize,
|
||||
WebSocketErrorInfo(),
|
||||
WebSocketOpenInfo(),
|
||||
WebSocketCloseInfo(code, reason, remote)));
|
||||
});
|
||||
}
|
||||
|
||||
@ -54,6 +55,7 @@ namespace ix
|
||||
std::lock_guard<std::mutex> lock(_configMutex);
|
||||
_url = url;
|
||||
}
|
||||
|
||||
void WebSocket::setExtraHeaders(const WebSocketHttpHeaders& headers)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_configMutex);
|
||||
@ -194,7 +196,7 @@ namespace ix
|
||||
return status;
|
||||
}
|
||||
|
||||
_onMessageCallback(std::make_unique<WebSocketMessage>(
|
||||
_onMessageCallback(ix::make_unique<WebSocketMessage>(
|
||||
WebSocketMessageType::Open,
|
||||
"",
|
||||
0,
|
||||
@ -226,12 +228,12 @@ namespace ix
|
||||
}
|
||||
|
||||
_onMessageCallback(
|
||||
std::make_unique<WebSocketMessage>(WebSocketMessageType::Open,
|
||||
"",
|
||||
0,
|
||||
WebSocketErrorInfo(),
|
||||
WebSocketOpenInfo(status.uri, status.headers),
|
||||
WebSocketCloseInfo()));
|
||||
ix::make_unique<WebSocketMessage>(WebSocketMessageType::Open,
|
||||
"",
|
||||
0,
|
||||
WebSocketErrorInfo(),
|
||||
WebSocketOpenInfo(status.uri, status.headers),
|
||||
WebSocketCloseInfo()));
|
||||
|
||||
if (_pingIntervalSecs > 0)
|
||||
{
|
||||
@ -311,12 +313,12 @@ namespace ix
|
||||
connectErr.reason = status.errorStr;
|
||||
connectErr.http_status = status.http_status;
|
||||
|
||||
_onMessageCallback(std::make_unique<WebSocketMessage>(WebSocketMessageType::Error,
|
||||
"",
|
||||
0,
|
||||
connectErr,
|
||||
WebSocketOpenInfo(),
|
||||
WebSocketCloseInfo()));
|
||||
_onMessageCallback(ix::make_unique<WebSocketMessage>(WebSocketMessageType::Error,
|
||||
"",
|
||||
0,
|
||||
connectErr,
|
||||
WebSocketOpenInfo(),
|
||||
WebSocketCloseInfo()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -387,13 +389,13 @@ namespace ix
|
||||
|
||||
bool binary = messageKind == WebSocketTransport::MessageKind::MSG_BINARY;
|
||||
|
||||
_onMessageCallback(std::make_unique<WebSocketMessage>(webSocketMessageType,
|
||||
msg,
|
||||
wireSize,
|
||||
webSocketErrorInfo,
|
||||
WebSocketOpenInfo(),
|
||||
WebSocketCloseInfo(),
|
||||
binary));
|
||||
_onMessageCallback(ix::make_unique<WebSocketMessage>(webSocketMessageType,
|
||||
msg,
|
||||
wireSize,
|
||||
webSocketErrorInfo,
|
||||
WebSocketOpenInfo(),
|
||||
WebSocketCloseInfo(),
|
||||
binary));
|
||||
|
||||
WebSocket::invokeTrafficTrackerCallback(wireSize, true);
|
||||
});
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "IXUrlParser.h"
|
||||
#include "IXUserAgent.h"
|
||||
#include "IXWebSocketHandshakeKeyGen.h"
|
||||
#include "IXStrCaseCompare.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
@ -35,9 +36,7 @@ namespace ix
|
||||
|
||||
bool WebSocketHandshake::insensitiveStringCompare(const std::string& a, const std::string& b)
|
||||
{
|
||||
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) {
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
return CaseInsensitiveLess::cmp(a, b);
|
||||
}
|
||||
|
||||
std::string WebSocketHandshake::genRandomString(const int len)
|
||||
|
@ -12,25 +12,6 @@
|
||||
|
||||
namespace ix
|
||||
{
|
||||
bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char& c1,
|
||||
const unsigned char& c2) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale());
|
||||
#else
|
||||
return std::tolower(c1) < std::tolower(c2);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CaseInsensitiveLess::operator()(const std::string& s1, const std::string& s2) const
|
||||
{
|
||||
return std::lexicographical_compare(s1.begin(),
|
||||
s1.end(), // source range
|
||||
s2.begin(),
|
||||
s2.end(), // dest range
|
||||
NocaseCompare()); // comparison
|
||||
}
|
||||
|
||||
std::pair<bool, WebSocketHttpHeaders> parseHttpHeaders(
|
||||
std::unique_ptr<Socket>& socket, const CancellationRequest& isCancellationRequested)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "IXCancellationRequest.h"
|
||||
#include "IXStrCaseCompare.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -15,17 +16,6 @@ namespace ix
|
||||
{
|
||||
class Socket;
|
||||
|
||||
struct CaseInsensitiveLess
|
||||
{
|
||||
// Case Insensitive compare_less binary function
|
||||
struct NocaseCompare
|
||||
{
|
||||
bool operator()(const unsigned char& c1, const unsigned char& c2) const;
|
||||
};
|
||||
|
||||
bool operator()(const std::string& s1, const std::string& s2) const;
|
||||
};
|
||||
|
||||
using WebSocketHttpHeaders = std::map<std::string, std::string, CaseInsensitiveLess>;
|
||||
|
||||
std::pair<bool, WebSocketHttpHeaders> parseHttpHeaders(
|
||||
|
@ -48,14 +48,15 @@
|
||||
|
||||
#include "IXWebSocketPerMessageDeflate.h"
|
||||
|
||||
#include "IXUniquePtr.h"
|
||||
#include "IXWebSocketPerMessageDeflateCodec.h"
|
||||
#include "IXWebSocketPerMessageDeflateOptions.h"
|
||||
|
||||
namespace ix
|
||||
{
|
||||
WebSocketPerMessageDeflate::WebSocketPerMessageDeflate()
|
||||
: _compressor(std::make_unique<WebSocketPerMessageDeflateCompressor>())
|
||||
, _decompressor(std::make_unique<WebSocketPerMessageDeflateDecompressor>())
|
||||
: _compressor(ix::make_unique<WebSocketPerMessageDeflateCompressor>())
|
||||
, _decompressor(ix::make_unique<WebSocketPerMessageDeflateDecompressor>())
|
||||
{
|
||||
;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "IXSocketFactory.h"
|
||||
#include "IXSocketTLSOptions.h"
|
||||
#include "IXUniquePtr.h"
|
||||
#include "IXUrlParser.h"
|
||||
#include "IXUtf8Validator.h"
|
||||
#include "IXWebSocketHandshake.h"
|
||||
@ -124,7 +125,7 @@ namespace ix
|
||||
std::string errorMsg;
|
||||
bool tls = protocol == "wss";
|
||||
_socket = createSocket(tls, -1, errorMsg, _socketTLSOptions);
|
||||
_perMessageDeflate = std::make_unique<WebSocketPerMessageDeflate>();
|
||||
_perMessageDeflate = ix::make_unique<WebSocketPerMessageDeflate>();
|
||||
|
||||
if (!_socket)
|
||||
{
|
||||
@ -177,7 +178,7 @@ namespace ix
|
||||
_blockingSend = true;
|
||||
|
||||
_socket = std::move(socket);
|
||||
_perMessageDeflate = std::make_unique<WebSocketPerMessageDeflate>();
|
||||
_perMessageDeflate = ix::make_unique<WebSocketPerMessageDeflate>();
|
||||
|
||||
WebSocketHandshake webSocketHandshake(_requestInitCancellation,
|
||||
_socket,
|
||||
|
@ -6,4 +6,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IX_WEBSOCKET_VERSION "10.4.0"
|
||||
#define IX_WEBSOCKET_VERSION "11.0.2"
|
||||
|
89
makefile
89
makefile
@ -28,11 +28,14 @@ brew:
|
||||
# server side ?) and I can't work-around it easily, so we're using mbedtls on
|
||||
# Linux for the SSL backend, which works great.
|
||||
ws_mbedtls_install:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_ZLIB=OFF -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
|
||||
|
||||
ws:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
|
||||
|
||||
ws_unity:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
|
||||
|
||||
ws_install:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 .. -DUSE_TEST=0 && ninja install)
|
||||
|
||||
@ -49,7 +52,7 @@ ws_no_ssl:
|
||||
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_WS=1 .. ; make -j 4)
|
||||
|
||||
ws_no_python:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; ninja install)
|
||||
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j4 install)
|
||||
|
||||
uninstall:
|
||||
xargs rm -fv < build/install_manifest.txt
|
||||
@ -107,71 +110,30 @@ format:
|
||||
test_server:
|
||||
(cd test && npm i ws && node broadcast-server.js)
|
||||
|
||||
# env TEST=Websocket_server make test
|
||||
# env TEST=Websocket_chat make test
|
||||
# env TEST=heartbeat make test
|
||||
build_test:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 .. ; ninja install)
|
||||
test:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 ..)
|
||||
(cd build ; ninja)
|
||||
(cd build ; ninja test)
|
||||
|
||||
test: build_test
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_make:
|
||||
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j 4)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_tsan:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableThreadSanitizer YES)
|
||||
(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_ubsan:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableUndefinedBehaviorSanitizer YES)
|
||||
(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_asan: build_test_asan
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
build_test_asan:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableAddressSanitizer YES)
|
||||
(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
|
||||
|
||||
test_tsan_openssl:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 -DUSE_OPEN_SSL=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableThreadSanitizer YES)
|
||||
(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_ubsan_openssl:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 -DUSE_OPEN_SSL=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableUndefinedBehaviorSanitizer YES)
|
||||
(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_tsan_openssl_release:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Release -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 -DUSE_OPEN_SSL=1 .. && xcodebuild -project ixwebsocket.xcodeproj -configuration Release -target ixwebsocket_unittest -enableThreadSanitizer YES)
|
||||
(cd build/test ; ln -sf Release/ixwebsocket_unittest)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
test_asan:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer")
|
||||
(cd build ; ninja)
|
||||
(cd build ; ctest -V .)
|
||||
|
||||
test_tsan_mbedtls:
|
||||
mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_TEST=1 -DUSE_MBED_TLS=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableThreadSanitizer YES)
|
||||
(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_MBED_TLS=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
|
||||
(cd build ; ninja)
|
||||
(cd build ; ninja test)
|
||||
|
||||
build_test_openssl:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_OPEN_SSL=1 -DUSE_TEST=1 .. ; ninja install)
|
||||
test_tsan_openssl:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_OPENS_SSL=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
|
||||
(cd build ; ninja)
|
||||
(cd build ; ninja test)
|
||||
|
||||
test_openssl: build_test_openssl
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
build_test_mbedtls:
|
||||
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_MBED_TLS=1 -DUSE_TEST=1 .. ; make -j 4)
|
||||
|
||||
test_mbedtls: build_test_mbedtls
|
||||
(cd test ; python2.7 run.py -r)
|
||||
|
||||
test_no_ssl:
|
||||
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TEST=1 .. ; make -j 4)
|
||||
(cd test ; python2.7 run.py -r)
|
||||
test_tsan_sectransport:
|
||||
mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_PYTHON=1 -DUSE_TLS=1 -DUSE_OPENS_SSL=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
|
||||
(cd build ; ninja)
|
||||
(cd build ; ninja test)
|
||||
|
||||
ws_test: ws
|
||||
(cd ws ; env DEBUG=1 PATH=../ws/build:$$PATH bash test_ws.sh)
|
||||
@ -247,6 +209,9 @@ doc:
|
||||
change: format
|
||||
vim ixwebsocket/IXWebSocketVersion.h docs/CHANGELOG.md
|
||||
|
||||
change_no_format:
|
||||
vim ixwebsocket/IXWebSocketVersion.h docs/CHANGELOG.md
|
||||
|
||||
commit:
|
||||
git commit -am "`sh tools/extract_latest_change.sh`"
|
||||
|
||||
|
@ -2,73 +2,44 @@
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
cmake_minimum_required (VERSION 3.4.1)
|
||||
cmake_minimum_required (VERSION 3.14)
|
||||
project (ixwebsocket_unittest)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if (MAC)
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../third_party/sanitizers-cmake/cmake" ${CMAKE_MODULE_PATH})
|
||||
find_package(Sanitizers)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
|
||||
set(CMAKE_LD_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}/Catch2/single_include
|
||||
../third_party
|
||||
../third_party/msgpack11
|
||||
../third_party/spdlog/include
|
||||
../ws
|
||||
)
|
||||
|
||||
add_definitions(-DSPDLOG_COMPILED_LIB=1)
|
||||
|
||||
find_package(JsonCpp)
|
||||
if (NOT JSONCPP_FOUND)
|
||||
include_directories(../third_party/jsoncpp)
|
||||
set(JSONCPP_SOURCES ../third_party/jsoncpp/jsoncpp.cpp)
|
||||
endif()
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
# Shared sources
|
||||
set (SOURCES
|
||||
${JSONCPP_SOURCES}
|
||||
|
||||
test_runner.cpp
|
||||
IXTest.cpp
|
||||
../third_party/msgpack11/msgpack11.cpp
|
||||
|
||||
IXSocketTest.cpp
|
||||
IXSocketConnectTest.cpp
|
||||
set (TEST_TARGET_NAMES
|
||||
IXSocketTest
|
||||
IXSocketConnectTest
|
||||
# IXWebSocketLeakTest.cpp # commented until we have a fix for #224
|
||||
IXWebSocketServerTest.cpp
|
||||
IXWebSocketTestConnectionDisconnection.cpp
|
||||
IXUrlParserTest.cpp
|
||||
IXWebSocketServerTest.cpp
|
||||
IXHttpClientTest.cpp
|
||||
IXHttpServerTest.cpp
|
||||
IXUnityBuildsTest.cpp
|
||||
IXHttpTest.cpp
|
||||
IXDNSLookupTest.cpp
|
||||
IXWebSocketSubProtocolTest.cpp
|
||||
IXSentryClientTest.cpp
|
||||
IXWebSocketChatTest.cpp
|
||||
IXWebSocketBroadcastTest.cpp
|
||||
IXWebSocketPerMessageDeflateCompressorTest.cpp
|
||||
IXStreamSqlTest.cpp
|
||||
IXWebSocketServerTest
|
||||
IXWebSocketTestConnectionDisconnection
|
||||
IXUrlParserTest
|
||||
IXHttpClientTest
|
||||
IXHttpServerTest
|
||||
IXUnityBuildsTest
|
||||
IXHttpTest
|
||||
IXDNSLookupTest
|
||||
IXWebSocketSubProtocolTest
|
||||
IXSentryClientTest
|
||||
IXWebSocketChatTest
|
||||
IXWebSocketBroadcastTest
|
||||
IXWebSocketPerMessageDeflateCompressorTest
|
||||
IXStreamSqlTest
|
||||
)
|
||||
|
||||
# Some unittest don't work on windows yet
|
||||
# Windows without TLS does not have hmac yet
|
||||
if (UNIX)
|
||||
list(APPEND SOURCES
|
||||
IXWebSocketCloseTest.cpp
|
||||
IXCobraChatTest.cpp
|
||||
IXCobraMetricsPublisherTest.cpp
|
||||
IXCobraToSentryBotTest.cpp
|
||||
IXCobraToStatsdBotTest.cpp
|
||||
IXCobraToStdoutBotTest.cpp
|
||||
list(APPEND TEST_TARGET_NAMES
|
||||
IXWebSocketCloseTest
|
||||
IXCobraChatTest
|
||||
IXCobraMetricsPublisherTest
|
||||
IXCobraToSentryBotTest
|
||||
IXCobraToStatsdBotTest
|
||||
IXCobraToStdoutBotTest
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -78,19 +49,9 @@ endif()
|
||||
|
||||
# Disable tests for now that are failing or not reliable
|
||||
|
||||
add_executable(ixwebsocket_unittest ${SOURCES})
|
||||
|
||||
if (MAC)
|
||||
add_sanitizers(ixwebsocket_unittest)
|
||||
endif()
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(ixwebsocket_unittest "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
if (JSONCPP_FOUND)
|
||||
target_include_directories(ixwebsocket_unittest PUBLIC ${JSONCPP_INCLUDE_DIRS})
|
||||
target_link_libraries(ixwebsocket_unittest ${JSONCPP_LIBRARIES})
|
||||
find_package(JsonCpp)
|
||||
if (NOT JSONCPP_FOUND)
|
||||
set(JSONCPP_SOURCES ../third_party/jsoncpp/jsoncpp.cpp)
|
||||
endif()
|
||||
|
||||
if (USE_PYTHON)
|
||||
@ -104,19 +65,69 @@ if (USE_PYTHON)
|
||||
message("Python_LIBRARIES:${Python_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# library with the most dependencies come first
|
||||
target_link_libraries(ixwebsocket_unittest ixbots)
|
||||
target_link_libraries(ixwebsocket_unittest ixsnake)
|
||||
target_link_libraries(ixwebsocket_unittest ixcobra)
|
||||
target_link_libraries(ixwebsocket_unittest ixsentry)
|
||||
target_link_libraries(ixwebsocket_unittest ixredis)
|
||||
target_link_libraries(ixwebsocket_unittest ixwebsocket)
|
||||
target_link_libraries(ixwebsocket_unittest ixcrypto)
|
||||
target_link_libraries(ixwebsocket_unittest ixcore)
|
||||
add_library(ixwebsocket_test)
|
||||
target_sources(ixwebsocket_test PRIVATE
|
||||
${JSONCPP_SOURCES}
|
||||
test_runner.cpp
|
||||
IXTest.cpp
|
||||
../third_party/msgpack11/msgpack11.cpp
|
||||
)
|
||||
target_compile_definitions(ixwebsocket_test PRIVATE ${TEST_PROGRAMS_DEFINITIONS})
|
||||
target_include_directories(ixwebsocket_test PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/Catch2/single_include
|
||||
../third_party
|
||||
)
|
||||
target_link_libraries(ixwebsocket_test ixsnake)
|
||||
target_link_libraries(ixwebsocket_test ixcobra)
|
||||
target_link_libraries(ixwebsocket_test ixwebsocket)
|
||||
target_link_libraries(ixwebsocket_test ixcrypto)
|
||||
target_link_libraries(ixwebsocket_test spdlog)
|
||||
|
||||
target_link_libraries(ixwebsocket_unittest spdlog)
|
||||
if (USE_PYTHON)
|
||||
target_link_libraries(ixwebsocket_unittest ${Python_LIBRARIES})
|
||||
endif()
|
||||
foreach(TEST_TARGET_NAME ${TEST_TARGET_NAMES})
|
||||
add_executable(${TEST_TARGET_NAME}
|
||||
${TEST_TARGET_NAME}.cpp
|
||||
)
|
||||
|
||||
install(TARGETS ixwebsocket_unittest DESTINATION bin)
|
||||
target_include_directories(${TEST_TARGET_NAME} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/Catch2/single_include
|
||||
../third_party
|
||||
../third_party/msgpack11
|
||||
)
|
||||
|
||||
target_compile_definitions(${TEST_TARGET_NAME} PRIVATE SPDLOG_COMPILED_LIB=1)
|
||||
|
||||
if (NOT JSONCPP_FOUND)
|
||||
target_include_directories(${TEST_TARGET_NAME} PRIVATE ../third_party/jsoncpp)
|
||||
endif()
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(${TEST_TARGET_NAME} "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
# library with the most dependencies come first
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixwebsocket_test)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixbots)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixsnake)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixcobra)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixsentry)
|
||||
|
||||
if (JSONCPP_FOUND)
|
||||
target_include_directories(${TEST_TARGET_NAME} PRIVATE ${JSONCPP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TEST_TARGET_NAME} ${JSONCPP_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixredis)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixwebsocket)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixcrypto)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ixcore)
|
||||
|
||||
target_link_libraries(${TEST_TARGET_NAME} spdlog)
|
||||
if (USE_PYTHON)
|
||||
target_link_libraries(${TEST_TARGET_NAME} ${Python_LIBRARIES})
|
||||
endif()
|
||||
|
||||
add_test(NAME ${TEST_TARGET_NAME}
|
||||
COMMAND ${TEST_TARGET_NAME}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
endforeach()
|
||||
|
@ -38,35 +38,6 @@ namespace
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
|
||||
{
|
||||
ix::CobraMetricsPublisher cobraMetricsPublisher;
|
||||
cobraMetricsPublisher.configure(config, channel);
|
||||
cobraMetricsPublisher.setSession(uuid4());
|
||||
cobraMetricsPublisher.enable(true);
|
||||
|
||||
Json::Value msg;
|
||||
msg["fps"] = 60;
|
||||
|
||||
cobraMetricsPublisher.setGenericAttributes("game", "ody");
|
||||
|
||||
// Wait a bit
|
||||
ix::msleep(500);
|
||||
|
||||
// publish some messages
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
|
||||
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
|
||||
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
|
||||
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
|
||||
ix::msleep(500);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
|
||||
|
@ -20,38 +20,6 @@
|
||||
|
||||
using namespace ix;
|
||||
|
||||
namespace
|
||||
{
|
||||
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
|
||||
{
|
||||
ix::CobraMetricsPublisher cobraMetricsPublisher;
|
||||
cobraMetricsPublisher.configure(config, channel);
|
||||
cobraMetricsPublisher.setSession(uuid4());
|
||||
cobraMetricsPublisher.enable(true);
|
||||
|
||||
Json::Value msg;
|
||||
msg["fps"] = 60;
|
||||
|
||||
cobraMetricsPublisher.setGenericAttributes("game", "ody");
|
||||
|
||||
// Wait a bit
|
||||
ix::msleep(500);
|
||||
|
||||
// publish some messages
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
|
||||
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
|
||||
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
|
||||
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
|
||||
ix::msleep(500);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
|
||||
{
|
||||
SECTION("Exchange and count sent/received messages.")
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <iostream>
|
||||
#include <ixbots/IXCobraToStdoutBot.h>
|
||||
#include <ixcobra/IXCobraConnection.h>
|
||||
#include <ixcobra/IXCobraMetricsPublisher.h>
|
||||
#include <ixcrypto/IXUuid.h>
|
||||
#include <ixredis/IXRedisServer.h>
|
||||
#include <ixsentry/IXSentryClient.h>
|
||||
@ -20,38 +19,6 @@
|
||||
|
||||
using namespace ix;
|
||||
|
||||
namespace
|
||||
{
|
||||
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
|
||||
{
|
||||
ix::CobraMetricsPublisher cobraMetricsPublisher;
|
||||
cobraMetricsPublisher.configure(config, channel);
|
||||
cobraMetricsPublisher.setSession(uuid4());
|
||||
cobraMetricsPublisher.enable(true);
|
||||
|
||||
Json::Value msg;
|
||||
msg["fps"] = 60;
|
||||
|
||||
cobraMetricsPublisher.setGenericAttributes("game", "ody");
|
||||
|
||||
// Wait a bit
|
||||
ix::msleep(500);
|
||||
|
||||
// publish some messages
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
|
||||
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
|
||||
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
|
||||
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
|
||||
ix::msleep(500);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Cobra_to_stdout_bot", "[cobra_bots]")
|
||||
{
|
||||
SECTION("Exchange and count sent/received messages.")
|
||||
|
@ -24,6 +24,8 @@ TEST_CASE("dns", "[net]")
|
||||
res = dnsLookup->resolve(errMsg, [] { return false; });
|
||||
std::cerr << "Error message: " << errMsg << std::endl;
|
||||
REQUIRE(res != nullptr);
|
||||
|
||||
dnsLookup->release(res);
|
||||
}
|
||||
|
||||
SECTION("Test resolving a non-existing hostname")
|
||||
|
@ -103,11 +103,11 @@ TEST_CASE("http server", "[httpd]")
|
||||
|
||||
std::cerr << "Status: " << response->statusCode << std::endl;
|
||||
std::cerr << "Error message: " << response->errorMsg << std::endl;
|
||||
std::cerr << "Payload: " << response->payload << std::endl;
|
||||
std::cerr << "Body: " << response->body << std::endl;
|
||||
|
||||
REQUIRE(response->errorCode == HttpErrorCode::Ok);
|
||||
REQUIRE(response->statusCode == 200);
|
||||
REQUIRE(response->payload == args->body);
|
||||
REQUIRE(response->body == args->body);
|
||||
|
||||
server.stop();
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <ixcobra/IXCobraMetricsPublisher.h>
|
||||
#include <ixcrypto/IXUuid.h>
|
||||
#include <ixwebsocket/IXNetSystem.h>
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <mutex>
|
||||
@ -243,4 +245,33 @@ namespace ix
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
void runPublisher(const ix::CobraConfig& config, const std::string& channel)
|
||||
{
|
||||
ix::CobraMetricsPublisher cobraMetricsPublisher;
|
||||
cobraMetricsPublisher.configure(config, channel);
|
||||
cobraMetricsPublisher.setSession(uuid4());
|
||||
cobraMetricsPublisher.enable(true);
|
||||
|
||||
Json::Value msg;
|
||||
msg["fps"] = 60;
|
||||
|
||||
cobraMetricsPublisher.setGenericAttributes("game", "ody");
|
||||
|
||||
// Wait a bit
|
||||
ix::msleep(500);
|
||||
|
||||
// publish some messages
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
|
||||
cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
|
||||
cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
|
||||
ix::msleep(500);
|
||||
|
||||
cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
|
||||
cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
|
||||
ix::msleep(500);
|
||||
}
|
||||
} // namespace ix
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <ixcobra/IXCobraConfig.h>
|
||||
#include <ixsnake/IXAppConfig.h>
|
||||
#include <ixwebsocket/IXGetFreePort.h>
|
||||
#include <ixwebsocket/IXSocketTLSOptions.h>
|
||||
@ -59,4 +60,6 @@ namespace ix
|
||||
std::string getWsScheme(bool preferTLS);
|
||||
|
||||
std::string makeCobraEndpoint(int port, bool preferTLS);
|
||||
|
||||
void runPublisher(const ix::CobraConfig& config, const std::string& channel);
|
||||
} // namespace ix
|
||||
|
@ -18,10 +18,10 @@ using namespace ix;
|
||||
|
||||
namespace
|
||||
{
|
||||
class WebSocketChat
|
||||
class WebSocketBroadcastChat
|
||||
{
|
||||
public:
|
||||
WebSocketChat(const std::string& user, const std::string& session, int port);
|
||||
WebSocketBroadcastChat(const std::string& user, const std::string& session, int port);
|
||||
|
||||
void subscribe(const std::string& channel);
|
||||
void start();
|
||||
@ -47,7 +47,9 @@ namespace
|
||||
mutable std::mutex _mutex;
|
||||
};
|
||||
|
||||
WebSocketChat::WebSocketChat(const std::string& user, const std::string& session, int port)
|
||||
WebSocketBroadcastChat::WebSocketBroadcastChat(const std::string& user,
|
||||
const std::string& session,
|
||||
int port)
|
||||
: _user(user)
|
||||
, _session(session)
|
||||
, _port(port)
|
||||
@ -55,35 +57,35 @@ namespace
|
||||
_webSocket.setTLSOptions(makeClientTLSOptions());
|
||||
}
|
||||
|
||||
size_t WebSocketChat::getReceivedMessagesCount() const
|
||||
size_t WebSocketBroadcastChat::getReceivedMessagesCount() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
return _receivedMessages.size();
|
||||
}
|
||||
|
||||
const std::vector<std::string>& WebSocketChat::getReceivedMessages() const
|
||||
const std::vector<std::string>& WebSocketBroadcastChat::getReceivedMessages() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
return _receivedMessages;
|
||||
}
|
||||
|
||||
void WebSocketChat::appendMessage(const std::string& message)
|
||||
void WebSocketBroadcastChat::appendMessage(const std::string& message)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_receivedMessages.push_back(message);
|
||||
}
|
||||
|
||||
bool WebSocketChat::isReady() const
|
||||
bool WebSocketBroadcastChat::isReady() const
|
||||
{
|
||||
return _webSocket.getReadyState() == ix::ReadyState::Open;
|
||||
}
|
||||
|
||||
void WebSocketChat::stop()
|
||||
void WebSocketBroadcastChat::stop()
|
||||
{
|
||||
_webSocket.stop();
|
||||
}
|
||||
|
||||
void WebSocketChat::start()
|
||||
void WebSocketBroadcastChat::start()
|
||||
{
|
||||
std::string url;
|
||||
{
|
||||
@ -156,7 +158,8 @@ namespace
|
||||
_webSocket.start();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> WebSocketChat::decodeMessage(const std::string& str)
|
||||
std::pair<std::string, std::string> WebSocketBroadcastChat::decodeMessage(
|
||||
const std::string& str)
|
||||
{
|
||||
std::string errMsg;
|
||||
MsgPack msg = MsgPack::parse(str, errMsg);
|
||||
@ -167,7 +170,7 @@ namespace
|
||||
return std::pair<std::string, std::string>(msg_user, msg_text);
|
||||
}
|
||||
|
||||
std::string WebSocketChat::encodeMessage(const std::string& text)
|
||||
std::string WebSocketBroadcastChat::encodeMessage(const std::string& text)
|
||||
{
|
||||
std::map<MsgPack, MsgPack> obj;
|
||||
obj["user"] = _user;
|
||||
@ -179,7 +182,7 @@ namespace
|
||||
return output;
|
||||
}
|
||||
|
||||
void WebSocketChat::sendMessage(const std::string& text)
|
||||
void WebSocketBroadcastChat::sendMessage(const std::string& text)
|
||||
{
|
||||
_webSocket.sendBinary(encodeMessage(text));
|
||||
}
|
||||
@ -248,11 +251,11 @@ TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
|
||||
REQUIRE(startServer(server, connectionId));
|
||||
|
||||
std::string session = ix::generateSessionId();
|
||||
std::vector<std::shared_ptr<WebSocketChat>> chatClients;
|
||||
std::vector<std::shared_ptr<WebSocketBroadcastChat>> chatClients;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
std::string user("user_" + std::to_string(i));
|
||||
chatClients.push_back(std::make_shared<WebSocketChat>(user, session, port));
|
||||
chatClients.push_back(std::make_shared<WebSocketBroadcastChat>(user, session, port));
|
||||
chatClients[i]->start();
|
||||
ix::msleep(50);
|
||||
}
|
||||
|
108
third_party/spdlog/.clang-format
vendored
108
third_party/spdlog/.clang-format
vendored
@ -1,108 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 140
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
54
third_party/spdlog/.clang-tidy
vendored
54
third_party/spdlog/.clang-tidy
vendored
@ -1,54 +0,0 @@
|
||||
Checks: 'cppcoreguidelines-*,
|
||||
performance-*,
|
||||
modernize-*,
|
||||
google-*,
|
||||
misc-*,
|
||||
cert-*,
|
||||
readability-*,
|
||||
clang-analyzer-*,
|
||||
-performance-unnecessary-value-param,
|
||||
-modernize-use-trailing-return-type,
|
||||
-google-runtime-references,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-readability-braces-around-statements,
|
||||
-google-readability-braces-around-statements,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-readability-magic-numbers,
|
||||
-readability-magic-numbers,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-modernize-avoid-c-arrays,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-readability-named-parameter,
|
||||
-cert-env33-c
|
||||
'
|
||||
|
||||
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: '*spdlog/[^f].*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: none
|
||||
|
||||
CheckOptions:
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||
value: '10'
|
||||
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||
value: '2'
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: '16'
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: 'NULL'
|
||||
|
1
third_party/spdlog/.gitattributes
vendored
1
third_party/spdlog/.gitattributes
vendored
@ -1 +0,0 @@
|
||||
* text=false
|
83
third_party/spdlog/.gitignore
vendored
83
third_party/spdlog/.gitignore
vendored
@ -1,83 +0,0 @@
|
||||
# Auto generated files
|
||||
build/*
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
*.suo
|
||||
*.tlog
|
||||
*.ilk
|
||||
*.log
|
||||
*.pdb
|
||||
*.idb
|
||||
*.iobj
|
||||
*.ipdb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Codelite
|
||||
.codelite
|
||||
|
||||
# KDevelop
|
||||
*.kdev4
|
||||
|
||||
# .orig files
|
||||
*.orig
|
||||
|
||||
# example files
|
||||
example/*
|
||||
!example/example.cpp
|
||||
!example/bench.cpp
|
||||
!example/utils.h
|
||||
!example/Makefile*
|
||||
!example/example.sln
|
||||
!example/example.vcxproj
|
||||
!example/CMakeLists.txt
|
||||
!example/meson.build
|
||||
!example/multisink.cpp
|
||||
!example/jni
|
||||
|
||||
# generated files
|
||||
generated
|
||||
|
||||
# Cmake
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
/tests/tests.VC.VC.opendb
|
||||
/tests/tests.VC.db
|
||||
/tests/tests
|
||||
/tests/logs/*
|
||||
|
||||
# idea
|
||||
.idea/
|
||||
cmake-build-*/
|
||||
*.db
|
||||
*.ipch
|
||||
*.filters
|
||||
*.db-wal
|
||||
*.opendb
|
||||
*.db-shm
|
||||
*.vcxproj
|
||||
*.tcl
|
||||
*.user
|
||||
*.sln
|
112
third_party/spdlog/.travis.yml
vendored
112
third_party/spdlog/.travis.yml
vendored
@ -1,112 +0,0 @@
|
||||
# Adapted from various sources, including:
|
||||
# - Louis Dionne's Hana: https://github.com/ldionne/hana
|
||||
# - Paul Fultz II's FIT: https://github.com/pfultz2/Fit
|
||||
# - Eric Niebler's range-v3: https://github.com/ericniebler/range-v3
|
||||
sudo: required
|
||||
language: cpp
|
||||
|
||||
# gcc 4.8
|
||||
addons: &gcc48
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
# gcc 7.0
|
||||
addons: &gcc7
|
||||
apt:
|
||||
packages:
|
||||
- g++-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
# Clang 3.5
|
||||
addons: &clang35
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.5
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.5
|
||||
|
||||
# Clang 7.0
|
||||
addons: &clang70
|
||||
apt:
|
||||
packages:
|
||||
- clang-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-7
|
||||
|
||||
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Test gcc-4.8: C++11, Build=Debug/Release
|
||||
- env: GCC_VERSION=4.8 BUILD_TYPE=Debug CPP=11
|
||||
os: linux
|
||||
addons: *gcc48
|
||||
|
||||
- env: GCC_VERSION=4.8 BUILD_TYPE=Release CPP=11
|
||||
os: linux
|
||||
addons: *gcc48
|
||||
|
||||
- env: GCC_VERSION=7 BUILD_TYPE=Release CPP=11
|
||||
os: linux
|
||||
addons: *gcc7
|
||||
|
||||
# Test clang-3.5: C++11, Build=Debug/Release
|
||||
- env: CLANG_VERSION=3.5 BUILD_TYPE=Debug CPP=11
|
||||
os: linux
|
||||
addons: *clang35
|
||||
|
||||
- env: CLANG_VERSION=3.5 BUILD_TYPE=Release CPP=11
|
||||
os: linux
|
||||
addons: *clang35
|
||||
|
||||
# Test clang-7.0: C++11, Build=Debug, ASAN=On
|
||||
- env: CLANG_VERSION=7 BUILD_TYPE=Debug CPP=11 ASAN=On TSAN=Off
|
||||
dist: bionic
|
||||
|
||||
- env: CLANG_VERSION=7 BUILD_TYPE=Release CPP=11 ASAN=On TSAN=Off
|
||||
dist: bionic
|
||||
|
||||
# osx
|
||||
- env: BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=Off
|
||||
os: osx
|
||||
|
||||
|
||||
|
||||
before_script:
|
||||
- if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
|
||||
- if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export CXX="clang++" CC="clang"; fi
|
||||
- which $CXX
|
||||
- which $CC
|
||||
- $CXX --version
|
||||
- cmake --version
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- mkdir -p build && cd build
|
||||
- |
|
||||
cmake .. \
|
||||
--warn-uninitialized \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_CXX_STANDARD=$CPP \
|
||||
-DSPDLOG_BUILD_EXAMPLE=ON \
|
||||
-DSPDLOG_BUILD_EXAMPLE_HO=ON \
|
||||
-DSPDLOG_ENABLE_WARNINGS=ON \
|
||||
-DSPDLOG_BUILD_BENCH=OFF \
|
||||
-DSPDLOG_BUILD_TESTS=ON \
|
||||
-DSPDLOG_BUILD_TESTS_HO=OFf \
|
||||
-DSPDLOG_SANITIZE_ADDRESS=$ASAN
|
||||
|
||||
- make VERBOSE=1 -j2
|
||||
- ctest -j2 --output-on-failure
|
||||
|
||||
|
||||
|
||||
notifications:
|
||||
email: false
|
335
third_party/spdlog/CMakeLists.txt
vendored
335
third_party/spdlog/CMakeLists.txt
vendored
@ -1,335 +0,0 @@
|
||||
# Copyright(c) 2019 spdlog authors
|
||||
# Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.11)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.11)
|
||||
endif()
|
||||
|
||||
ENABLE_LANGUAGE(C)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Start spdlog project
|
||||
#---------------------------------------------------------------------------------------
|
||||
include(cmake/utils.cmake)
|
||||
include(cmake/ide.cmake)
|
||||
|
||||
spdlog_extract_version()
|
||||
|
||||
project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX)
|
||||
message(STATUS "Build spdlog: ${SPDLOG_VERSION}")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Set default build to release
|
||||
#---------------------------------------------------------------------------------------
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
|
||||
endif()
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Compiler config
|
||||
#---------------------------------------------------------------------------------------
|
||||
if (NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN")
|
||||
set(CMAKE_CXX_EXTENSIONS ON)
|
||||
endif()
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Check if spdlog is being used directly or via add_subdirectory, but allow overriding
|
||||
if (NOT DEFINED SPDLOG_MASTER_PROJECT)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(SPDLOG_MASTER_PROJECT ON)
|
||||
else()
|
||||
set(SPDLOG_MASTER_PROJECT OFF)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# build shared option
|
||||
option(SPDLOG_BUILD_SHARED "Build shared library" OFF)
|
||||
|
||||
# precompiled headers option
|
||||
option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled header to speed up compilation time" OFF)
|
||||
|
||||
# example options
|
||||
option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT})
|
||||
option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF)
|
||||
|
||||
# testing options
|
||||
option(SPDLOG_BUILD_TESTS "Build tests" OFF)
|
||||
option(SPDLOG_BUILD_TESTS_HO "Build tests using the header only version" OFF)
|
||||
|
||||
# bench options
|
||||
option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" OFF)
|
||||
|
||||
# sanitizer options
|
||||
option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF)
|
||||
|
||||
# warning options
|
||||
option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF)
|
||||
|
||||
# install options
|
||||
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
|
||||
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
|
||||
option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF)
|
||||
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
|
||||
|
||||
if (SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO)
|
||||
message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
|
||||
endif()
|
||||
|
||||
# misc tweakme options
|
||||
if(WIN32)
|
||||
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
|
||||
option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
option(SPDLOG_CLOCK_COARSE "Use the much faster (but much less accurate) CLOCK_REALTIME_COARSE instead of the regular clock," OFF)
|
||||
endif()
|
||||
|
||||
option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF)
|
||||
option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF)
|
||||
option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF)
|
||||
option(SPDLOG_NO_ATOMIC_LEVELS "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" OFF)
|
||||
|
||||
# clang-tidy
|
||||
if(${CMAKE_VERSION} VERSION_GREATER "3.5")
|
||||
option(SPDLOG_TIDY "run clang-tidy" OFF)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_TIDY)
|
||||
set(CMAKE_CXX_CLANG_TIDY "clang-tidy")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
message(STATUS "Enabled clang-tidy")
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Static/Shared library (shared not supported in windows yet)
|
||||
#---------------------------------------------------------------------------------------
|
||||
set(SPDLOG_SRCS
|
||||
src/spdlog.cpp
|
||||
src/stdout_sinks.cpp
|
||||
src/color_sinks.cpp
|
||||
src/file_sinks.cpp
|
||||
src/async.cpp
|
||||
src/cfg.cpp)
|
||||
|
||||
if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
|
||||
list(APPEND SPDLOG_SRCS src/fmt.cpp)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND SPDLOG_BUILD_SHARED)
|
||||
list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||
endif()
|
||||
|
||||
if (SPDLOG_BUILD_SHARED)
|
||||
add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB)
|
||||
if(WIN32)
|
||||
target_compile_options(spdlog PUBLIC /wd4251 /wd4275)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY)
|
||||
endif()
|
||||
if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
|
||||
target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED)
|
||||
endif()
|
||||
else()
|
||||
add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS})
|
||||
endif()
|
||||
|
||||
add_library(spdlog::spdlog ALIAS spdlog)
|
||||
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB)
|
||||
target_include_directories(spdlog PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
target_link_libraries(spdlog PUBLIC Threads::Threads)
|
||||
spdlog_enable_warnings(spdlog)
|
||||
|
||||
set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION ${SPDLOG_VERSION_MAJOR})
|
||||
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d)
|
||||
|
||||
if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pch.h.in ${PROJECT_BINARY_DIR}/spdlog_pch.h @ONLY)
|
||||
target_precompile_headers(spdlog PRIVATE ${PROJECT_BINARY_DIR}/spdlog_pch.h)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Header only version
|
||||
#---------------------------------------------------------------------------------------
|
||||
add_library(spdlog_header_only INTERFACE)
|
||||
add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only)
|
||||
|
||||
target_include_directories(spdlog_header_only INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
target_link_libraries(spdlog_header_only INTERFACE Threads::Threads)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Use fmt package if using external fmt
|
||||
#---------------------------------------------------------------------------------------
|
||||
if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
|
||||
if (NOT TARGET fmt::fmt)
|
||||
find_package(fmt REQUIRED)
|
||||
endif ()
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL)
|
||||
|
||||
# use external fmt-header-nly
|
||||
if(SPDLOG_FMT_EXTERNAL_HO)
|
||||
target_link_libraries(spdlog PUBLIC fmt::fmt-header-only)
|
||||
target_link_libraries(spdlog_header_only INTERFACE fmt::fmt-header-only)
|
||||
else() # use external compile fmt
|
||||
target_link_libraries(spdlog PUBLIC fmt::fmt)
|
||||
target_link_libraries(spdlog_header_only INTERFACE fmt::fmt)
|
||||
endif()
|
||||
|
||||
set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Misc definitions according to tweak options
|
||||
#---------------------------------------------------------------------------------------
|
||||
if(SPDLOG_WCHAR_SUPPORT)
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_WCHAR_FILENAMES)
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_FILENAMES)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_FILENAMES)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_NO_EXCEPTIONS)
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_NO_EXCEPTIONS)
|
||||
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_EXCEPTIONS)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(spdlog PRIVATE -fno-exceptions)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SPDLOG_CLOCK_COARSE)
|
||||
target_compile_definitions(spdlog PRIVATE SPDLOG_CLOCK_COARSE)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_CLOCK_COARSE)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_PREVENT_CHILD_FD)
|
||||
target_compile_definitions(spdlog PRIVATE SPDLOG_PREVENT_CHILD_FD)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_PREVENT_CHILD_FD)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_NO_THREAD_ID)
|
||||
target_compile_definitions(spdlog PRIVATE SPDLOG_NO_THREAD_ID)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_THREAD_ID)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_NO_TLS)
|
||||
target_compile_definitions(spdlog PRIVATE SPDLOG_NO_TLS)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_TLS)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_NO_ATOMIC_LEVELS)
|
||||
target_compile_definitions(spdlog PUBLIC SPDLOG_NO_ATOMIC_LEVELS)
|
||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_ATOMIC_LEVELS)
|
||||
endif()
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Build binaries
|
||||
#---------------------------------------------------------------------------------------
|
||||
if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO)
|
||||
message(STATUS "Generating example(s)")
|
||||
add_subdirectory(example)
|
||||
spdlog_enable_warnings(example)
|
||||
if(SPDLOG_BUILD_EXAMPLE_HO)
|
||||
spdlog_enable_warnings(example_header_only)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO)
|
||||
message(STATUS "Generating tests")
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if(SPDLOG_BUILD_BENCH)
|
||||
message(STATUS "Generating benchmarks")
|
||||
add_subdirectory(bench)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Install
|
||||
#---------------------------------------------------------------------------------------
|
||||
if (SPDLOG_INSTALL)
|
||||
message(STATUS "Generating install")
|
||||
set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in")
|
||||
set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake")
|
||||
set(config_targets_file "spdlogConfigTargets.cmake")
|
||||
set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake")
|
||||
set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/spdlog")
|
||||
set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc")
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Include files
|
||||
#---------------------------------------------------------------------------------------
|
||||
install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE)
|
||||
install(TARGETS spdlog spdlog_header_only EXPORT spdlog
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
|
||||
install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/")
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Install pkg-config file
|
||||
#---------------------------------------------------------------------------------------
|
||||
get_target_property(PKG_CONFIG_DEFINES spdlog INTERFACE_COMPILE_DEFINITIONS)
|
||||
string(REPLACE ";" " -D" PKG_CONFIG_DEFINES "${PKG_CONFIG_DEFINES}")
|
||||
string(CONCAT PKG_CONFIG_DEFINES "-D" "${PKG_CONFIG_DEFINES}")
|
||||
configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY)
|
||||
install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}")
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Install CMake config files
|
||||
#---------------------------------------------------------------------------------------
|
||||
install(EXPORT spdlog
|
||||
DESTINATION ${export_dest_dir}
|
||||
NAMESPACE spdlog::
|
||||
FILE ${config_targets_file})
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_file("${project_config_in}" "${project_config_out}" @ONLY)
|
||||
|
||||
write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
|
||||
install(FILES
|
||||
"${project_config_out}"
|
||||
"${version_config_file}" DESTINATION "${export_dest_dir}")
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Support creation of installable packages
|
||||
#---------------------------------------------------------------------------------------
|
||||
include(cmake/spdlogCPack.cmake)
|
||||
endif ()
|
||||
|
24
third_party/spdlog/INSTALL
vendored
24
third_party/spdlog/INSTALL
vendored
@ -1,24 +0,0 @@
|
||||
Header only version:
|
||||
==================================================================
|
||||
Just copy the files to your build tree and use a C++11 compiler.
|
||||
Or use CMake:
|
||||
add_executable(example_header_only example.cpp)
|
||||
target_link_libraries(example_header_only spdlog::spdlog_header_only)
|
||||
|
||||
|
||||
Compiled library version:
|
||||
==================================================================
|
||||
CMake:
|
||||
add_executable(example example.cpp)
|
||||
target_link_libraries(example spdlog::spdlog)
|
||||
|
||||
Or copy src/spdlog.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler.
|
||||
|
||||
Tested on:
|
||||
gcc 4.8.1 and above
|
||||
clang 3.5
|
||||
Visual Studio 2013
|
||||
|
||||
|
||||
|
||||
|
26
third_party/spdlog/LICENSE
vendored
26
third_party/spdlog/LICENSE
vendored
@ -1,26 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Gabi Melman.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
-- NOTE: Third party dependecy used by this sofware --
|
||||
This software depends on the fmt lib (MIT License),
|
||||
and users must comply to its license: https://github.com/fmtlib/fmt/blob/master/LICENSE.rst
|
||||
|
406
third_party/spdlog/README.md
vendored
406
third_party/spdlog/README.md
vendored
@ -1,406 +0,0 @@
|
||||
# spdlog
|
||||
|
||||
Very fast, header-only/compiled, C++ logging library. [](https://travis-ci.org/gabime/spdlog) [](https://ci.appveyor.com/project/gabime/spdlog) [](https://github.com/gabime/spdlog/releases/latest)
|
||||
|
||||
## Install
|
||||
#### Header only version
|
||||
Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler.
|
||||
|
||||
#### Static lib version (recommended - much faster compile times)
|
||||
```console
|
||||
$ git clone https://github.com/gabime/spdlog.git
|
||||
$ cd spdlog && mkdir build && cd build
|
||||
$ cmake .. && make -j
|
||||
```
|
||||
|
||||
see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use.
|
||||
|
||||
## Platforms
|
||||
* Linux, FreeBSD, OpenBSD, Solaris, AIX
|
||||
* Windows (msvc 2013+, cygwin)
|
||||
* macOS (clang 3.5+)
|
||||
* Android
|
||||
|
||||
## Package managers:
|
||||
* Homebrew: `brew install spdlog`
|
||||
* MacPorts: `sudo port install spdlog`
|
||||
* FreeBSD: `cd /usr/ports/devel/spdlog/ && make install clean`
|
||||
* Fedora: `yum install spdlog`
|
||||
* Gentoo: `emerge dev-libs/spdlog`
|
||||
* Arch Linux: `pacman -S spdlog`
|
||||
* vcpkg: `vcpkg install spdlog`
|
||||
* conan: `spdlog/[>=1.4.1]`
|
||||
* conda: `conda install -c conda-forge spdlog`
|
||||
|
||||
|
||||
## Features
|
||||
* Very fast (see [benchmarks](#benchmarks) below).
|
||||
* Headers only or compiled version
|
||||
* Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library.
|
||||
* **New!** [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand.
|
||||
* Asynchronous mode (optional)
|
||||
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
|
||||
* Multi/Single threaded loggers.
|
||||
* Various log targets:
|
||||
* Rotating log files.
|
||||
* Daily log files.
|
||||
* Console logging (colors supported).
|
||||
* syslog.
|
||||
* Windows debugger (```OutputDebugString(..)```)
|
||||
* Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface).
|
||||
* Log filtering - log levels can be modified in runtime as well as in compile time.
|
||||
* Support for loading log levels from argv or from environment var.
|
||||
|
||||
|
||||
## Usage samples
|
||||
|
||||
#### Basic usage
|
||||
```c++
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
spdlog::info("Welcome to spdlog!");
|
||||
spdlog::error("Some error message with arg: {}", 1);
|
||||
|
||||
spdlog::warn("Easy padding in numbers like {:08d}", 12);
|
||||
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||
spdlog::info("Support for floats {:03.2f}", 1.23456);
|
||||
spdlog::info("Positional args are {1} {0}..", "too", "supported");
|
||||
spdlog::info("{:<30}", "left aligned");
|
||||
|
||||
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
|
||||
spdlog::debug("This message should be displayed..");
|
||||
|
||||
// change log pattern
|
||||
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
|
||||
|
||||
// Compile time log levels
|
||||
// define SPDLOG_ACTIVE_LEVEL to desired level
|
||||
SPDLOG_TRACE("Some trace message with param {}", 42);
|
||||
SPDLOG_DEBUG("Some debug message");
|
||||
|
||||
// Set the default logger to file logger
|
||||
auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
|
||||
spdlog::set_default_logger(file_logger);
|
||||
}
|
||||
|
||||
```
|
||||
#### Load log levels from env variable or from argv
|
||||
```c++
|
||||
#include "spdlog/cfg/env.h"
|
||||
void load_levels_example()
|
||||
{
|
||||
// Set the log level to "info" and mylogger to to "trace":
|
||||
// SPDLOG_LEVEL=info,mylogger=trace && ./example
|
||||
spdlog::cfg::load_env_levels();
|
||||
// or from command line:
|
||||
// ./example SPDLOG_LEVEL=info,mylogger=trace
|
||||
// #include "spdlog/cfg/argv.h" // for loading levels from argv
|
||||
// spdlog::cfg::load_argv_levels(args, argv);
|
||||
}
|
||||
```
|
||||
#### Create stdout/stderr logger object
|
||||
```c++
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
void stdout_example()
|
||||
{
|
||||
// create color multi threaded logger
|
||||
auto console = spdlog::stdout_color_mt("console");
|
||||
auto err_logger = spdlog::stderr_color_mt("stderr");
|
||||
spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
|
||||
}
|
||||
```
|
||||
---
|
||||
#### Basic file logger
|
||||
```c++
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
void basic_logfile_example()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
|
||||
}
|
||||
catch (const spdlog::spdlog_ex &ex)
|
||||
{
|
||||
std::cout << "Log init failed: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
#### Rotating files
|
||||
```c++
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
void rotating_example()
|
||||
{
|
||||
// Create a file rotating logger with 5mb size max and 3 rotated files
|
||||
auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
#### Daily files
|
||||
```c++
|
||||
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
void daily_example()
|
||||
{
|
||||
// Create a daily logger - a new file is created every day on 2:30am
|
||||
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
#### Backtrace support
|
||||
```c++
|
||||
// Loggers can store in a ring buffer all messages (including debug/trace) and display later on demand.
|
||||
// When needed, call dump_backtrace() to see them
|
||||
spdlog::enable_backtrace(32); // create ring buffer with capacity of 32 messages
|
||||
// or my_logger->enable_backtrace(32)..
|
||||
for(int i = 0; i < 100; i++)
|
||||
{
|
||||
spdlog::debug("Backtrace message {}", i); // not logged yet..
|
||||
}
|
||||
// e.g. if some error happened:
|
||||
spdlog::dump_backtrace(); // log them now! show the last 32 messages
|
||||
|
||||
// or my_logger->dump_backtrace(32)..
|
||||
```
|
||||
|
||||
---
|
||||
#### Periodic flush
|
||||
```c++
|
||||
// periodically flush all *registered* loggers every 3 seconds:
|
||||
// warning: only use if all your loggers are thread safe ("_mt" loggers)
|
||||
spdlog::flush_every(std::chrono::seconds(3));
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
#### Log binary data in hex
|
||||
```c++
|
||||
// many types of std::container<char> types can be used.
|
||||
// ranges are supported too.
|
||||
// format flags:
|
||||
// {:X} - print in uppercase.
|
||||
// {:s} - don't separate each byte with space.
|
||||
// {:p} - don't print the position on each line start.
|
||||
// {:n} - don't split the output to lines.
|
||||
|
||||
#include "spdlog/fmt/bin_to_hex.h"
|
||||
|
||||
void binary_example()
|
||||
{
|
||||
auto console = spdlog::get("console");
|
||||
std::array<char, 80> buf;
|
||||
console->info("Binary example: {}", spdlog::to_hex(buf));
|
||||
console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
|
||||
// more examples:
|
||||
// logger->info("uppercase: {:X}", spdlog::to_hex(buf));
|
||||
// logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
|
||||
// logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
#### Logger with multi sinks - each with different format and log level
|
||||
```c++
|
||||
|
||||
// create logger with 2 targets with different log levels and formats.
|
||||
// the console will show only warnings or errors, while the file will log all.
|
||||
void multi_sink_example()
|
||||
{
|
||||
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||
console_sink->set_level(spdlog::level::warn);
|
||||
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
|
||||
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
|
||||
file_sink->set_level(spdlog::level::trace);
|
||||
|
||||
spdlog::logger logger("multi_sink", {console_sink, file_sink});
|
||||
logger.set_level(spdlog::level::debug);
|
||||
logger.warn("this should appear in both console and file");
|
||||
logger.info("this message should not appear in the console, only in the file");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
#### Asynchronous logging
|
||||
```c++
|
||||
#include "spdlog/async.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
void async_example()
|
||||
{
|
||||
// default thread pool settings can be modified *before* creating the async logger:
|
||||
// spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread.
|
||||
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
|
||||
// alternatively:
|
||||
// auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
#### Asynchronous logger with multi sinks
|
||||
```c++
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
|
||||
void multi_sink_example2()
|
||||
{
|
||||
spdlog::init_thread_pool(8192, 1);
|
||||
auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
|
||||
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
|
||||
std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink};
|
||||
auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
|
||||
spdlog::register_logger(logger);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
#### User defined types
|
||||
```c++
|
||||
// user defined types logging by implementing operator<<
|
||||
#include "spdlog/fmt/ostr.h" // must be included
|
||||
struct my_type
|
||||
{
|
||||
int i;
|
||||
template<typename OStream>
|
||||
friend OStream &operator<<(OStream &os, const my_type &c)
|
||||
{
|
||||
return os << "[my_type i=" << c.i << "]";
|
||||
}
|
||||
};
|
||||
|
||||
void user_defined_example()
|
||||
{
|
||||
spdlog::get("console")->info("user defined type: {}", my_type{14});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
#### User defined flags in the log pattern
|
||||
```c++
|
||||
// Log patterns can contain custom flags.
|
||||
// the following example will add new flag '%*' - which will be bound to a <my_formatter_flag> instance.
|
||||
#include "spdlog/pattern_formatter.h"
|
||||
class my_formatter_flag : public spdlog::custom_flag_formatter
|
||||
{
|
||||
public:
|
||||
void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
|
||||
{
|
||||
std::string some_txt = "custom-flag";
|
||||
dest.append(some_txt.data(), some_txt.data() + some_txt.size());
|
||||
}
|
||||
|
||||
std::unique_ptr<custom_flag_formatter> clone() const override
|
||||
{
|
||||
return spdlog::details::make_unique<my_formatter_flag>();
|
||||
}
|
||||
};
|
||||
|
||||
void custom_flags_example()
|
||||
{
|
||||
auto formatter = std::make_unique<spdlog::pattern_formatter>();
|
||||
formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
|
||||
spdlog::set_formatter(std::move(formatter));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
#### Custom error handler
|
||||
```c++
|
||||
void err_handler_example()
|
||||
{
|
||||
// can be set globally or per logger(logger->set_error_handler(..))
|
||||
spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); });
|
||||
spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
#### syslog
|
||||
```c++
|
||||
#include "spdlog/sinks/syslog_sink.h"
|
||||
void syslog_example()
|
||||
{
|
||||
std::string ident = "spdlog-example";
|
||||
auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
|
||||
syslog_logger->warn("This is warning that will end up in syslog.");
|
||||
}
|
||||
```
|
||||
---
|
||||
#### Android example
|
||||
```c++
|
||||
#include "spdlog/sinks/android_sink.h"
|
||||
void android_example()
|
||||
{
|
||||
std::string tag = "spdlog-android";
|
||||
auto android_logger = spdlog::android_logger_mt("android", tag);
|
||||
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz
|
||||
|
||||
#### Synchronous mode
|
||||
```
|
||||
[info] **************************************************************
|
||||
[info] Single thread, 1,000,000 iterations
|
||||
[info] **************************************************************
|
||||
[info] basic_st Elapsed: 0.17 secs 5,777,626/sec
|
||||
[info] rotating_st Elapsed: 0.18 secs 5,475,894/sec
|
||||
[info] daily_st Elapsed: 0.20 secs 5,062,659/sec
|
||||
[info] empty_logger Elapsed: 0.07 secs 14,127,300/sec
|
||||
[info] **************************************************************
|
||||
[info] C-string (400 bytes). Single thread, 1,000,000 iterations
|
||||
[info] **************************************************************
|
||||
[info] basic_st Elapsed: 0.41 secs 2,412,483/sec
|
||||
[info] rotating_st Elapsed: 0.72 secs 1,389,196/sec
|
||||
[info] daily_st Elapsed: 0.42 secs 2,393,298/sec
|
||||
[info] null_st Elapsed: 0.04 secs 27,446,957/sec
|
||||
[info] **************************************************************
|
||||
[info] 10 threads, competing over the same logger object, 1,000,000 iterations
|
||||
[info] **************************************************************
|
||||
[info] basic_mt Elapsed: 0.60 secs 1,659,613/sec
|
||||
[info] rotating_mt Elapsed: 0.62 secs 1,612,493/sec
|
||||
[info] daily_mt Elapsed: 0.61 secs 1,638,305/sec
|
||||
[info] null_mt Elapsed: 0.16 secs 6,272,758/sec
|
||||
```
|
||||
#### ASynchronous mode
|
||||
```
|
||||
[info] -------------------------------------------------
|
||||
[info] Messages : 1,000,000
|
||||
[info] Threads : 10
|
||||
[info] Queue : 8,192 slots
|
||||
[info] Queue memory : 8,192 x 272 = 2,176 KB
|
||||
[info] -------------------------------------------------
|
||||
[info]
|
||||
[info] *********************************
|
||||
[info] Queue Overflow Policy: block
|
||||
[info] *********************************
|
||||
[info] Elapsed: 1.70784 secs 585,535/sec
|
||||
[info] Elapsed: 1.69805 secs 588,910/sec
|
||||
[info] Elapsed: 1.7026 secs 587,337/sec
|
||||
[info]
|
||||
[info] *********************************
|
||||
[info] Queue Overflow Policy: overrun
|
||||
[info] *********************************
|
||||
[info] Elapsed: 0.372816 secs 2,682,285/sec
|
||||
[info] Elapsed: 0.379758 secs 2,633,255/sec
|
||||
[info] Elapsed: 0.373532 secs 2,677,147/sec
|
||||
|
||||
```
|
||||
|
||||
## Documentation
|
||||
Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages.
|
38
third_party/spdlog/appveyor.yml
vendored
38
third_party/spdlog/appveyor.yml
vendored
@ -1,38 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2017
|
||||
environment:
|
||||
matrix:
|
||||
- GENERATOR: '"Visual Studio 14 2015"'
|
||||
BUILD_TYPE: Debug
|
||||
WCHAR: 'OFF'
|
||||
- GENERATOR: '"Visual Studio 14 2015"'
|
||||
BUILD_TYPE: Release
|
||||
WCHAR: 'ON'
|
||||
- GENERATOR: '"Visual Studio 14 2015 Win64"'
|
||||
BUILD_TYPE: Debug
|
||||
WCHAR: 'ON'
|
||||
- GENERATOR: '"Visual Studio 14 2015 Win64"'
|
||||
BUILD_TYPE: Release
|
||||
WCHAR: 'ON'
|
||||
- GENERATOR: '"Visual Studio 15 2017 Win64"'
|
||||
BUILD_TYPE: Debug
|
||||
WCHAR: 'ON'
|
||||
- GENERATOR: '"Visual Studio 15 2017 Win64"'
|
||||
BUILD_TYPE: Release
|
||||
WCHAR: 'OFf'
|
||||
build_script:
|
||||
- cmd: >-
|
||||
set
|
||||
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
set PATH=%PATH%:C:\Program Files\Git\usr\bin
|
||||
|
||||
cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_WCHAR_SUPPORT=%WCHAR% -DSPDLOG_BUILD_EXAMPLE=ON -DSPDLOG_BUILD_EXAMPLE_HO=ON -DSPDLOG_BUILD_TESTS=ON -DSPDLOG_BUILD_TESTS_HO=OFF -DSPDLOG_ENABLE_WARNINGS=ON
|
||||
|
||||
cmake --build . --config %BUILD_TYPE%
|
||||
|
||||
test_script:
|
||||
- ctest -VV -C "%BUILD_TYPE%"
|
26
third_party/spdlog/bench/CMakeLists.txt
vendored
26
third_party/spdlog/bench/CMakeLists.txt
vendored
@ -1,26 +0,0 @@
|
||||
# Copyright(c) 2019 spdlog authors
|
||||
# Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(spdlog_bench CXX)
|
||||
|
||||
if(NOT TARGET spdlog)
|
||||
# Stand-alone build
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(benchmark CONFIG REQUIRED)
|
||||
|
||||
add_executable(bench bench.cpp)
|
||||
spdlog_enable_warnings(bench)
|
||||
target_link_libraries(bench PRIVATE spdlog::spdlog)
|
||||
|
||||
add_executable(async_bench async_bench.cpp)
|
||||
target_link_libraries(async_bench PRIVATE spdlog::spdlog)
|
||||
|
||||
add_executable(latency latency.cpp)
|
||||
target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog)
|
||||
|
||||
add_executable(formatter-bench formatter-bench.cpp)
|
||||
target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog)
|
179
third_party/spdlog/bench/async_bench.cpp
vendored
179
third_party/spdlog/bench/async_bench.cpp
vendored
@ -1,179 +0,0 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
//
|
||||
// bench.cpp : spdlog benchmarks
|
||||
//
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/async.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
using namespace spdlog;
|
||||
using namespace spdlog::sinks;
|
||||
using namespace utils;
|
||||
|
||||
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // disable fopen warning under msvc
|
||||
#endif // _MSC_VER
|
||||
|
||||
int count_lines(const char *filename)
|
||||
{
|
||||
int counter = 0;
|
||||
auto *infile = fopen(filename, "r");
|
||||
int ch;
|
||||
while (EOF != (ch = getc(infile)))
|
||||
{
|
||||
if ('\n' == ch)
|
||||
counter++;
|
||||
}
|
||||
fclose(infile);
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void verify_file(const char *filename, int expected_count)
|
||||
{
|
||||
spdlog::info("Verifying {} to contain {:n} line..", filename, expected_count);
|
||||
auto count = count_lines(filename);
|
||||
if (count != expected_count)
|
||||
{
|
||||
spdlog::error("Test failed. {} has {:n} lines instead of {:n}", filename, count, expected_count);
|
||||
exit(1);
|
||||
}
|
||||
spdlog::info("Line count OK ({:n})\n", count);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
int howmany = 1000000;
|
||||
int queue_size = std::min(howmany + 2, 8192);
|
||||
int threads = 10;
|
||||
int iters = 3;
|
||||
|
||||
try
|
||||
{
|
||||
spdlog::set_pattern("[%^%l%$] %v");
|
||||
if (argc == 1)
|
||||
{
|
||||
spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
howmany = atoi(argv[1]);
|
||||
if (argc > 2)
|
||||
threads = atoi(argv[2]);
|
||||
if (argc > 3)
|
||||
{
|
||||
queue_size = atoi(argv[3]);
|
||||
if (queue_size > 500000)
|
||||
{
|
||||
spdlog::error("Max queue size allowed: 500,000");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 4)
|
||||
iters = atoi(argv[4]);
|
||||
|
||||
auto slot_size = sizeof(spdlog::details::async_msg);
|
||||
spdlog::info("-------------------------------------------------");
|
||||
spdlog::info("Messages : {:n}", howmany);
|
||||
spdlog::info("Threads : {:n}", threads);
|
||||
spdlog::info("Queue : {:n} slots", queue_size);
|
||||
spdlog::info("Queue memory : {:n} x {} = {:n} KB ", queue_size, slot_size, (queue_size * slot_size) / 1024);
|
||||
spdlog::info("Total iters : {:n}", iters);
|
||||
spdlog::info("-------------------------------------------------");
|
||||
|
||||
const char *filename = "logs/basic_async.log";
|
||||
spdlog::info("");
|
||||
spdlog::info("*********************************");
|
||||
spdlog::info("Queue Overflow Policy: block");
|
||||
spdlog::info("*********************************");
|
||||
for (int i = 0; i < iters; i++)
|
||||
{
|
||||
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
||||
auto logger = std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block);
|
||||
bench_mt(howmany, std::move(logger), threads);
|
||||
// verify_file(filename, howmany);
|
||||
}
|
||||
|
||||
spdlog::info("");
|
||||
spdlog::info("*********************************");
|
||||
spdlog::info("Queue Overflow Policy: overrun");
|
||||
spdlog::info("*********************************");
|
||||
// do same test but discard oldest if queue is full instead of blocking
|
||||
filename = "logs/basic_async-overrun.log";
|
||||
for (int i = 0; i < iters; i++)
|
||||
{
|
||||
auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
||||
auto logger =
|
||||
std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::overrun_oldest);
|
||||
bench_mt(howmany, std::move(logger), threads);
|
||||
}
|
||||
spdlog::shutdown();
|
||||
}
|
||||
catch (std::exception &ex)
|
||||
{
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
perror("Last error");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void thread_fun(std::shared_ptr<spdlog::logger> logger, int howmany)
|
||||
{
|
||||
for (int i = 0; i < howmany; i++)
|
||||
{
|
||||
logger->info("Hello logger: msg number {}", i);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> logger, int thread_count)
|
||||
{
|
||||
using std::chrono::high_resolution_clock;
|
||||
vector<thread> threads;
|
||||
auto start = high_resolution_clock::now();
|
||||
|
||||
int msgs_per_thread = howmany / thread_count;
|
||||
int msgs_per_thread_mod = howmany % thread_count;
|
||||
for (int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
if (t == 0 && msgs_per_thread_mod)
|
||||
threads.push_back(std::thread(thread_fun, logger, msgs_per_thread + msgs_per_thread_mod));
|
||||
else
|
||||
threads.push_back(std::thread(thread_fun, logger, msgs_per_thread));
|
||||
}
|
||||
|
||||
for (auto &t : threads)
|
||||
{
|
||||
t.join();
|
||||
};
|
||||
|
||||
auto delta = high_resolution_clock::now() - start;
|
||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||
spdlog::info("Elapsed: {} secs\t {:n}/sec", delta_d, int(howmany / delta_d));
|
||||
}
|
238
third_party/spdlog/bench/bench.cpp
vendored
238
third_party/spdlog/bench/bench.cpp
vendored
@ -1,238 +0,0 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
//
|
||||
// bench.cpp : spdlog benchmarks
|
||||
//
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
#include "spdlog/sinks/null_sink.h"
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include <atomic>
|
||||
#include <cstdlib> // EXIT_FAILURE
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
void bench(int howmany, std::shared_ptr<spdlog::logger> log);
|
||||
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);
|
||||
|
||||
// void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log);
|
||||
// void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log);
|
||||
|
||||
static const size_t file_size = 30 * 1024 * 1024;
|
||||
static const size_t rotating_files = 5;
|
||||
static const int max_threads = 1000;
|
||||
|
||||
void bench_threaded_logging(int threads, int iters)
|
||||
{
|
||||
spdlog::info("**************************************************************");
|
||||
spdlog::info("Multi threaded: {:n} threads, {:n} messages", threads, iters);
|
||||
spdlog::info("**************************************************************");
|
||||
|
||||
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true);
|
||||
bench_mt(iters, std::move(basic_mt), threads);
|
||||
auto basic_mt_tracing = spdlog::basic_logger_mt("basic_mt/backtrace-on", "logs/basic_mt.log", true);
|
||||
basic_mt_tracing->enable_backtrace(32);
|
||||
bench_mt(iters, std::move(basic_mt_tracing), threads);
|
||||
|
||||
spdlog::info("");
|
||||
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files);
|
||||
bench_mt(iters, std::move(rotating_mt), threads);
|
||||
auto rotating_mt_tracing = spdlog::rotating_logger_mt("rotating_mt/backtrace-on", "logs/rotating_mt.log", file_size, rotating_files);
|
||||
rotating_mt_tracing->enable_backtrace(32);
|
||||
bench_mt(iters, std::move(rotating_mt_tracing), threads);
|
||||
|
||||
spdlog::info("");
|
||||
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log");
|
||||
bench_mt(iters, std::move(daily_mt), threads);
|
||||
auto daily_mt_tracing = spdlog::daily_logger_mt("daily_mt/backtrace-on", "logs/daily_mt.log");
|
||||
daily_mt_tracing->enable_backtrace(32);
|
||||
bench_mt(iters, std::move(daily_mt_tracing), threads);
|
||||
|
||||
spdlog::info("");
|
||||
auto empty_logger = std::make_shared<spdlog::logger>("level-off");
|
||||
empty_logger->set_level(spdlog::level::off);
|
||||
bench(iters, empty_logger);
|
||||
auto empty_logger_tracing = std::make_shared<spdlog::logger>("level-off/backtrace-on");
|
||||
empty_logger_tracing->set_level(spdlog::level::off);
|
||||
empty_logger_tracing->enable_backtrace(32);
|
||||
bench(iters, empty_logger_tracing);
|
||||
}
|
||||
|
||||
void bench_single_threaded(int iters)
|
||||
{
|
||||
spdlog::info("**************************************************************");
|
||||
spdlog::info("Single threaded: {:n} messages", iters);
|
||||
spdlog::info("**************************************************************");
|
||||
|
||||
auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true);
|
||||
bench(iters, std::move(basic_st));
|
||||
|
||||
auto basic_st_tracing = spdlog::basic_logger_st("basic_st/backtrace-on", "logs/basic_st.log", true);
|
||||
bench(iters, std::move(basic_st_tracing));
|
||||
|
||||
spdlog::info("");
|
||||
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
|
||||
bench(iters, std::move(rotating_st));
|
||||
auto rotating_st_tracing = spdlog::rotating_logger_st("rotating_st/backtrace-on", "logs/rotating_st.log", file_size, rotating_files);
|
||||
rotating_st_tracing->enable_backtrace(32);
|
||||
bench(iters, std::move(rotating_st_tracing));
|
||||
|
||||
spdlog::info("");
|
||||
auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
|
||||
bench(iters, std::move(daily_st));
|
||||
auto daily_st_tracing = spdlog::daily_logger_st("daily_st/backtrace-on", "logs/daily_st.log");
|
||||
daily_st_tracing->enable_backtrace(32);
|
||||
bench(iters, std::move(daily_st_tracing));
|
||||
|
||||
spdlog::info("");
|
||||
auto empty_logger = std::make_shared<spdlog::logger>("level-off");
|
||||
empty_logger->set_level(spdlog::level::off);
|
||||
bench(iters, empty_logger);
|
||||
|
||||
auto empty_logger_tracing = std::make_shared<spdlog::logger>("level-off/backtrace-on");
|
||||
empty_logger_tracing->set_level(spdlog::level::off);
|
||||
empty_logger_tracing->enable_backtrace(32);
|
||||
bench(iters, empty_logger_tracing);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
spdlog::set_automatic_registration(false);
|
||||
spdlog::default_logger()->set_pattern("[%^%l%$] %v");
|
||||
int iters = 250000;
|
||||
int threads = 4;
|
||||
try
|
||||
{
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
iters = std::stoi(argv[1]);
|
||||
}
|
||||
if (argc > 2)
|
||||
{
|
||||
threads = std::stoi(argv[2]);
|
||||
}
|
||||
|
||||
if (threads > max_threads)
|
||||
{
|
||||
throw std::runtime_error(fmt::format("Number of threads exceeds maximum({}})", max_threads));
|
||||
}
|
||||
|
||||
bench_single_threaded(iters);
|
||||
bench_threaded_logging(1, iters);
|
||||
bench_threaded_logging(threads, iters);
|
||||
}
|
||||
catch (std::exception &ex)
|
||||
{
|
||||
spdlog::error(ex.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void bench(int howmany, std::shared_ptr<spdlog::logger> log)
|
||||
{
|
||||
using std::chrono::duration;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::high_resolution_clock;
|
||||
|
||||
auto start = high_resolution_clock::now();
|
||||
for (auto i = 0; i < howmany; ++i)
|
||||
{
|
||||
log->info("Hello logger: msg number {}", i);
|
||||
}
|
||||
|
||||
auto delta = high_resolution_clock::now() - start;
|
||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||
|
||||
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d));
|
||||
spdlog::drop(log->name());
|
||||
}
|
||||
|
||||
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
|
||||
{
|
||||
using std::chrono::duration;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::high_resolution_clock;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(thread_count);
|
||||
auto start = high_resolution_clock::now();
|
||||
for (int t = 0; t < thread_count; ++t)
|
||||
{
|
||||
threads.emplace_back([&]() {
|
||||
for (int j = 0; j < howmany / thread_count; j++)
|
||||
{
|
||||
log->info("Hello logger: msg number {}", j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto &t : threads)
|
||||
{
|
||||
t.join();
|
||||
};
|
||||
|
||||
auto delta = high_resolution_clock::now() - start;
|
||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d));
|
||||
spdlog::drop(log->name());
|
||||
}
|
||||
|
||||
/*
|
||||
void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log)
|
||||
{
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::duration;
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
auto orig_default = spdlog::default_logger();
|
||||
spdlog::set_default_logger(log);
|
||||
auto start = high_resolution_clock::now();
|
||||
for (auto i = 0; i < howmany; ++i)
|
||||
{
|
||||
spdlog::info("Hello logger: msg number {}", i);
|
||||
}
|
||||
|
||||
auto delta = high_resolution_clock::now() - start;
|
||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||
spdlog::drop(log->name());
|
||||
spdlog::set_default_logger(std::move(orig_default));
|
||||
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d));
|
||||
}
|
||||
|
||||
void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log)
|
||||
{
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::duration;
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
|
||||
"lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem "
|
||||
"libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed "
|
||||
"augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare "
|
||||
"nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis.";
|
||||
|
||||
auto orig_default = spdlog::default_logger();
|
||||
spdlog::set_default_logger(log);
|
||||
auto start = high_resolution_clock::now();
|
||||
for (auto i = 0; i < howmany; ++i)
|
||||
{
|
||||
spdlog::log(spdlog::level::info, msg);
|
||||
}
|
||||
|
||||
auto delta = high_resolution_clock::now() - start;
|
||||
auto delta_d = duration_cast<duration<double>>(delta).count();
|
||||
spdlog::drop(log->name());
|
||||
spdlog::set_default_logger(std::move(orig_default));
|
||||
spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d));
|
||||
}
|
||||
|
||||
*/
|
80
third_party/spdlog/bench/formatter-bench.cpp
vendored
80
third_party/spdlog/bench/formatter-bench.cpp
vendored
@ -1,80 +0,0 @@
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/pattern_formatter.h"
|
||||
|
||||
void bench_formatter(benchmark::State &state, std::string pattern)
|
||||
{
|
||||
auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern);
|
||||
spdlog::memory_buf_t dest;
|
||||
std::string logger_name = "logger-name";
|
||||
const char *text = "Hello. This is some message with length of 80 ";
|
||||
|
||||
spdlog::source_loc source_loc{"a/b/c/d/myfile.cpp", 123, "some_func()"};
|
||||
spdlog::details::log_msg msg(source_loc, logger_name, spdlog::level::info, text);
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
dest.clear();
|
||||
formatter->format(msg, dest);
|
||||
benchmark::DoNotOptimize(dest);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_formatters()
|
||||
{
|
||||
// basic patterns(single flag)
|
||||
std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEisg@luioO%";
|
||||
std::vector<std::string> basic_patterns;
|
||||
for (auto &flag : all_flags)
|
||||
{
|
||||
auto pattern = std::string("%") + flag;
|
||||
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
|
||||
|
||||
// pattern = std::string("%16") + flag;
|
||||
// benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
|
||||
//
|
||||
// // bench center padding
|
||||
// pattern = std::string("%=16") + flag;
|
||||
// benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
|
||||
}
|
||||
|
||||
// complex patterns
|
||||
std::vector<std::string> patterns = {
|
||||
"[%D %X] [%l] [%n] %v",
|
||||
"[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v",
|
||||
"[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v",
|
||||
};
|
||||
for (auto &pattern : patterns)
|
||||
{
|
||||
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern)->Iterations(2500000);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
spdlog::set_pattern("[%^%l%$] %v");
|
||||
if (argc != 2)
|
||||
{
|
||||
spdlog::error("Usage: {} <pattern> (or \"all\" to bench all)", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string pattern = argv[1];
|
||||
if (pattern == "all")
|
||||
{
|
||||
bench_formatters();
|
||||
}
|
||||
else
|
||||
{
|
||||
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
|
||||
}
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
166
third_party/spdlog/bench/latency.cpp
vendored
166
third_party/spdlog/bench/latency.cpp
vendored
@ -1,166 +0,0 @@
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
//
|
||||
// latency.cpp : spdlog latency benchmarks
|
||||
//
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/async.h"
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
#include "spdlog/sinks/null_sink.h"
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
|
||||
void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
|
||||
{
|
||||
const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
|
||||
"lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem "
|
||||
"libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed "
|
||||
"augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare "
|
||||
"nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis.";
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
logger->info(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
|
||||
{
|
||||
int i = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
logger->info("Hello logger: msg number {}...............", ++i);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
|
||||
{
|
||||
int i = 0;
|
||||
benchmark::DoNotOptimize(i); // prevent unused warnings
|
||||
benchmark::DoNotOptimize(logger); // prevent unused warnings
|
||||
for (auto _ : state)
|
||||
{
|
||||
SPDLOG_LOGGER_DEBUG(logger, "Hello logger: msg number {}...............", i++);
|
||||
SPDLOG_DEBUG("Hello logger: msg number {}...............", i++);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
void bench_dev_null()
|
||||
{
|
||||
auto dev_null_st = spdlog::basic_logger_st("/dev/null_st", "/dev/null");
|
||||
benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))->UseRealTime();
|
||||
spdlog::drop("/dev/null_st");
|
||||
|
||||
auto dev_null_mt = spdlog::basic_logger_mt("/dev/null_mt", "/dev/null");
|
||||
benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))->UseRealTime();
|
||||
spdlog::drop("/dev/null_mt");
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
using spdlog::sinks::null_sink_mt;
|
||||
using spdlog::sinks::null_sink_st;
|
||||
|
||||
size_t file_size = 30 * 1024 * 1024;
|
||||
size_t rotating_files = 5;
|
||||
int n_threads = benchmark::CPUInfo::Get().num_cpus;
|
||||
|
||||
auto full_bench = argc > 1 && std::string(argv[1]) == "full";
|
||||
|
||||
// disabled loggers
|
||||
auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
|
||||
disabled_logger->set_level(spdlog::level::off);
|
||||
benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger);
|
||||
benchmark::RegisterBenchmark("disabled-at-runtime", bench_logger, disabled_logger);
|
||||
// with backtrace of 64
|
||||
auto tracing_disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
|
||||
tracing_disabled_logger->enable_backtrace(64);
|
||||
benchmark::RegisterBenchmark("disabled-at-runtime/backtrace", bench_logger, tracing_disabled_logger);
|
||||
|
||||
auto null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());
|
||||
benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string, std::move(null_logger_st));
|
||||
benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger_st);
|
||||
// with backtrace of 64
|
||||
auto tracing_null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>());
|
||||
tracing_null_logger_st->enable_backtrace(64);
|
||||
benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st);
|
||||
|
||||
#ifdef __linux
|
||||
bench_dev_null();
|
||||
#endif // __linux__
|
||||
|
||||
if (full_bench)
|
||||
{
|
||||
// basic_st
|
||||
auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true);
|
||||
benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime();
|
||||
spdlog::drop("basic_st");
|
||||
// with backtrace of 64
|
||||
auto tracing_basic_st = spdlog::basic_logger_st("tracing_basic_st", "latency_logs/tracing_basic_st.log", true);
|
||||
tracing_basic_st->enable_backtrace(64);
|
||||
benchmark::RegisterBenchmark("basic_st/backtrace", bench_logger, std::move(tracing_basic_st))->UseRealTime();
|
||||
spdlog::drop("tracing_basic_st");
|
||||
|
||||
// rotating st
|
||||
auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files);
|
||||
benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime();
|
||||
spdlog::drop("rotating_st");
|
||||
// with backtrace of 64
|
||||
auto tracing_rotating_st =
|
||||
spdlog::rotating_logger_st("tracing_rotating_st", "latency_logs/tracing_rotating_st.log", file_size, rotating_files);
|
||||
benchmark::RegisterBenchmark("rotating_st/backtrace", bench_logger, std::move(tracing_rotating_st))->UseRealTime();
|
||||
spdlog::drop("tracing_rotating_st");
|
||||
|
||||
// daily st
|
||||
auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log");
|
||||
benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime();
|
||||
spdlog::drop("daily_st");
|
||||
auto tracing_daily_st = spdlog::daily_logger_mt("tracing_daily_st", "latency_logs/daily_st.log");
|
||||
benchmark::RegisterBenchmark("daily_st/backtrace", bench_logger, std::move(tracing_daily_st))->UseRealTime();
|
||||
spdlog::drop("tracing_daily_st");
|
||||
|
||||
//
|
||||
// Multi threaded bench, 10 loggers using same logger concurrently
|
||||
//
|
||||
auto null_logger_mt = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
|
||||
benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime();
|
||||
|
||||
// basic_mt
|
||||
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true);
|
||||
benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime();
|
||||
spdlog::drop("basic_mt");
|
||||
|
||||
// rotating mt
|
||||
auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files);
|
||||
benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime();
|
||||
spdlog::drop("rotating_mt");
|
||||
|
||||
// daily mt
|
||||
auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log");
|
||||
benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime();
|
||||
spdlog::drop("daily_mt");
|
||||
}
|
||||
|
||||
// async
|
||||
auto queue_size = 1024 * 1024 * 3;
|
||||
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
|
||||
auto async_logger = std::make_shared<spdlog::async_logger>(
|
||||
"async_logger", std::make_shared<null_sink_mt>(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest);
|
||||
benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)->Threads(n_threads)->UseRealTime();
|
||||
|
||||
auto async_logger_tracing = std::make_shared<spdlog::async_logger>(
|
||||
"async_logger_tracing", std::make_shared<null_sink_mt>(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest);
|
||||
async_logger_tracing->enable_backtrace(32);
|
||||
benchmark::RegisterBenchmark("async_logger/tracing", bench_logger, async_logger_tracing)->Threads(n_threads)->UseRealTime();
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
14
third_party/spdlog/bench/meson.build
vendored
14
third_party/spdlog/bench/meson.build
vendored
@ -1,14 +0,0 @@
|
||||
benchmark = dependency('benchmark')
|
||||
|
||||
bench_matrix = [
|
||||
['bench', [spdlog_dep], []],
|
||||
['async_bench', [spdlog_dep], []],
|
||||
['formatter-bench', [spdlog_dep, benchmark], ['all']],
|
||||
['latency', [spdlog_dep, benchmark], []],
|
||||
]
|
||||
|
||||
foreach i : bench_matrix
|
||||
bench_exe = executable(i[0], i[0] + '.cpp', dependencies: i[1])
|
||||
benchmark('bench_' + i[0], bench_exe, args: i[2])
|
||||
endforeach
|
||||
|
34
third_party/spdlog/bench/utils.h
vendored
34
third_party/spdlog/bench/utils.h
vendored
@ -1,34 +0,0 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<typename T>
|
||||
inline std::string format(const T &value)
|
||||
{
|
||||
static std::locale loc("");
|
||||
std::stringstream ss;
|
||||
ss.imbue(loc);
|
||||
ss << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string format(const double &value)
|
||||
{
|
||||
static std::locale loc("");
|
||||
std::stringstream ss;
|
||||
ss.imbue(loc);
|
||||
ss << std::fixed << std::setprecision(1) << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace utils
|
18
third_party/spdlog/cmake/ide.cmake
vendored
18
third_party/spdlog/cmake/ide.cmake
vendored
@ -1,18 +0,0 @@
|
||||
#---------------------------------------------------------------------------------------
|
||||
# IDE support for headers
|
||||
#---------------------------------------------------------------------------------------
|
||||
set(SPDLOG_HEADERS_DIR "${CMAKE_CURRENT_LIST_DIR}/../include")
|
||||
|
||||
file(GLOB SPDLOG_TOP_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/*.h")
|
||||
file(GLOB SPDLOG_DETAILS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/details/*.h")
|
||||
file(GLOB SPDLOG_SINKS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/sinks/*.h")
|
||||
file(GLOB SPDLOG_FMT_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/*.h")
|
||||
file(GLOB SPDLOG_FMT_BUNDELED_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/bundled/*.h")
|
||||
set(SPDLOG_ALL_HEADERS ${SPDLOG_TOP_HEADERS} ${SPDLOG_DETAILS_HEADERS} ${SPDLOG_SINKS_HEADERS} ${SPDLOG_FMT_HEADERS} ${SPDLOG_FMT_BUNDELED_HEADERS})
|
||||
|
||||
source_group("Header Files\\spdlog" FILES ${SPDLOG_TOP_HEADERS})
|
||||
source_group("Header Files\\spdlog\\details" FILES ${SPDLOG_DETAILS_HEADERS})
|
||||
source_group("Header Files\\spdlog\\sinks" FILES ${SPDLOG_SINKS_HEADERS})
|
||||
source_group("Header Files\\spdlog\\fmt" FILES ${SPDLOG_FMT_HEADERS})
|
||||
source_group("Header Files\\spdlog\\fmt\\bundled\\" FILES ${SPDLOG_FMT_BUNDELED_HEADERS})
|
||||
|
258
third_party/spdlog/cmake/pch.h.in
vendored
258
third_party/spdlog/cmake/pch.h.in
vendored
@ -1,258 +0,0 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
// details/pattern_formatter-inl.h
|
||||
// fmt/bin_to_hex.h
|
||||
// fmt/bundled/format-inl.h
|
||||
#include <cctype>
|
||||
|
||||
// details/file_helper-inl.h
|
||||
// details/os-inl.h
|
||||
// fmt/bundled/core.h
|
||||
// fmt/bundled/posix.h
|
||||
// logger-inl.h
|
||||
// sinks/daily_file_sink.h
|
||||
// sinks/stdout_sinks.h
|
||||
#include <cstdio>
|
||||
|
||||
// details/os-inl.h
|
||||
// fmt/bundled/posix.h
|
||||
#include <cstdlib>
|
||||
|
||||
// details/os-inl.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// fmt/bundled/core.h
|
||||
// fmt/bundled/format-inl.h
|
||||
#include <cstring>
|
||||
|
||||
// details/os-inl.h
|
||||
// details/os.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/pattern_formatter.h
|
||||
// fmt/bundled/chrono.h
|
||||
// sinks/daily_file_sink.h
|
||||
// sinks/rotating_file_sink-inl.h
|
||||
#include <ctime>
|
||||
|
||||
// fmt/bundled/format-inl.h
|
||||
#include <climits>
|
||||
|
||||
// fmt/bundled/format-inl.h
|
||||
#include <cwchar>
|
||||
|
||||
// fmt/bundled/format-inl.h
|
||||
// fmt/bundled/format.h
|
||||
#include <cmath>
|
||||
|
||||
// fmt/bundled/format-inl.h
|
||||
#include <cstdarg>
|
||||
|
||||
// details/file_helper-inl.h
|
||||
// fmt/bundled/format.h
|
||||
// fmt/bundled/posix.h
|
||||
// sinks/rotating_file_sink-inl.h
|
||||
#include <cerrno>
|
||||
|
||||
// details/circular_q.h
|
||||
// details/thread_pool-inl.h
|
||||
// fmt/bundled/format-inl.h
|
||||
#include <cassert>
|
||||
|
||||
// async_logger-inl.h
|
||||
// cfg/helpers-inl.h
|
||||
// log_levels.h
|
||||
// common.h
|
||||
// details/file_helper-inl.h
|
||||
// details/log_msg.h
|
||||
// details/os-inl.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/pattern_formatter.h
|
||||
// details/registry-inl.h
|
||||
// details/registry.h
|
||||
// details/tcp_client-windows.h
|
||||
// details/tcp_client.h
|
||||
// fmt/bundled/core.h
|
||||
// sinks/android_sink.h
|
||||
// sinks/ansicolor_sink.h
|
||||
// sinks/basic_file_sink.h
|
||||
// sinks/daily_file_sink.h
|
||||
// sinks/dup_filter_sink.h
|
||||
// sinks/msvc_sink.h
|
||||
// sinks/ringbuffer_sink.h
|
||||
// sinks/rotating_file_sink-inl.h
|
||||
// sinks/rotating_file_sink.h
|
||||
// sinks/syslog_sink.h
|
||||
// sinks/tcp_sink.h
|
||||
// sinks/win_eventlog_sink.h
|
||||
// sinks/wincolor_sink.h
|
||||
// spdlog.h:
|
||||
#include <string>
|
||||
|
||||
// cfg/helpers-inl.h
|
||||
// fmt/bundled/chrono.h
|
||||
#include <sstream>
|
||||
|
||||
// fmt/bundled/ostream.h
|
||||
// sinks/ostream_sink.h
|
||||
#include <ostream>
|
||||
|
||||
// cfg/log_levels.h
|
||||
// details/registry-inl.h
|
||||
// details/registry.h
|
||||
#include <unordered_map>
|
||||
|
||||
// details/circular_q.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/pattern_formatter.h
|
||||
// details/thread_pool.h
|
||||
// fmt/bundled/compile.h
|
||||
// logger.h
|
||||
// sinks/dist_sink.h
|
||||
// sinks/ringbuffer_sink.h
|
||||
// sinks/win_eventlog_sink.h
|
||||
#include <vector>
|
||||
|
||||
// details/os-inl.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// sinks/ansicolor_sink.h
|
||||
// sinks/syslog_sink.h
|
||||
// sinks/systemd_sink.h
|
||||
// sinks/wincolor_sink.h
|
||||
#include <array>
|
||||
|
||||
// details/file_helper-inl.h
|
||||
// details/file_helper.h
|
||||
// sinks/rotating_file_sink-inl.h
|
||||
#include <tuple>
|
||||
|
||||
// details/os-inl.h
|
||||
// fmt/bundled/format.h
|
||||
// fmt/bundled/printf.h
|
||||
#include <limits>
|
||||
|
||||
// common.h
|
||||
// details/backtracer.h
|
||||
// details/null_mutex.h
|
||||
#include <atomic>
|
||||
|
||||
// common.h
|
||||
// details/backtracer.h
|
||||
// details/null_mutex.h
|
||||
#include <locale>
|
||||
|
||||
// common.h
|
||||
#include <initializer_list>
|
||||
|
||||
// common.h
|
||||
#include <exception>
|
||||
|
||||
// common.h
|
||||
// details/fmt_helper.h
|
||||
// fmt/bundled/core.h
|
||||
// fmt/bundled/ranges.h
|
||||
#include <type_traits>
|
||||
|
||||
// cfg/helpers-inl.h
|
||||
// details/null_mutex.h
|
||||
// details/pattern_formatter-inl.h
|
||||
#include <utility>
|
||||
|
||||
// async.h
|
||||
// async_logger-inl.h
|
||||
// common.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/pattern_formatter.h
|
||||
// details/registry-inl.h
|
||||
// details/registry.h
|
||||
// details/thread_pool.h
|
||||
// fmt/bundled/format.h
|
||||
// sinks/ansicolor_sink.h
|
||||
// sinks/base_sink-inl.h
|
||||
// sinks/dist_sink.h
|
||||
// sinks/stdout_sinks-inl.h
|
||||
// sinks/wincolor_sink.h
|
||||
// spdlog.h
|
||||
#include <memory>
|
||||
|
||||
// async.h
|
||||
// common.h
|
||||
// details/backtracer.h
|
||||
// details/periodic_worker.h
|
||||
// details/registry-inl.h
|
||||
// details/registry.h
|
||||
// details/thread_pool.h
|
||||
// sinks/tcp_sink.h
|
||||
// spdlog.h
|
||||
#include <functional>
|
||||
|
||||
// details/mpmc_blocking_q.h
|
||||
// details/periodic_worker.h
|
||||
#include <condition_variable>
|
||||
|
||||
// details/os-inl.h
|
||||
// fmt/bundled/format.h
|
||||
// fmt/bundled/printf.h
|
||||
// sinks/dist_sink.h
|
||||
#include <algorithm>
|
||||
|
||||
// common.h
|
||||
// details/file_helper-inl.h
|
||||
// details/fmt_helper.h
|
||||
// details/os-inl.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/pattern_formatter.h
|
||||
// details/periodic_worker.h
|
||||
// details/registry-inl.h
|
||||
// details/registry.h
|
||||
// details/thread_pool.h
|
||||
// fmt/bundled/chrono.h
|
||||
// sinks/android_sink.h
|
||||
// sinks/daily_file_sink.h
|
||||
// sinks/dup_filter_sink.h
|
||||
// sinks/rotating_file_sink-inl.h
|
||||
// sinks/rotating_file_sink.h
|
||||
// sinks/tcp_sink.h
|
||||
// spdlog.h
|
||||
#include <chrono>
|
||||
|
||||
// details/file_helper-inl.h
|
||||
// details/os-inl.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/periodic_worker.h
|
||||
// details/thread_pool.h
|
||||
// sinks/android_sink.h
|
||||
#include <thread>
|
||||
|
||||
// async.h
|
||||
// details/backtracer.h
|
||||
// details/console_globals.h
|
||||
// details/mpmc_blocking_q.h
|
||||
// details/pattern_formatter-inl.h
|
||||
// details/periodic_worker.h
|
||||
// details/registry.h
|
||||
// sinks/android_sink.h
|
||||
// sinks/ansicolor_sink.h
|
||||
// sinks/basic_file_sink.h
|
||||
// sinks/daily_file_sink.h
|
||||
// sinks/dist_sink.h
|
||||
// sinks/dup_filter_sink.h
|
||||
// sinks/msvc_sink.h
|
||||
// sinks/null_sink.h
|
||||
// sinks/ostream_sink.h
|
||||
// sinks/ringbuffer_sink.h
|
||||
// sinks/rotating_file_sink-inl.h
|
||||
// sinks/rotating_file_sink.h
|
||||
// sinks/tcp_sink.h
|
||||
// sinks/win_eventlog_sink.h
|
||||
// sinks/wincolor_sink.h
|
||||
//
|
||||
// color_sinks.cpp
|
||||
// file_sinks.cpp
|
||||
// spdlog.cpp
|
||||
// stdout_sinks.cpp
|
||||
#include <mutex>
|
||||
|
||||
// spdlog
|
||||
#include <spdlog/common.h>
|
13
third_party/spdlog/cmake/spdlog.pc.in
vendored
13
third_party/spdlog/cmake/spdlog.pc.in
vendored
@ -1,13 +0,0 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/include
|
||||
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
|
||||
Name: lib@PROJECT_NAME@
|
||||
Description: Fast C++ logging library.
|
||||
URL: https://github.com/gabime/@PROJECT_NAME@
|
||||
Version: @SPDLOG_VERSION@
|
||||
CFlags: -I${includedir} @PKG_CONFIG_DEFINES@
|
||||
Libs: -L${libdir} -lspdlog -pthread
|
||||
Requires: @PKG_CONFIG_REQUIRES@
|
||||
|
50
third_party/spdlog/cmake/spdlogCPack.cmake
vendored
50
third_party/spdlog/cmake/spdlogCPack.cmake
vendored
@ -1,50 +0,0 @@
|
||||
set(CPACK_GENERATOR "TGZ;ZIP" CACHE STRING "Semicolon separated list of generators")
|
||||
|
||||
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
|
||||
set(CPACK_INSTALL_CMAKE_PROJECTS
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${PROJECT_NAME}"
|
||||
ALL
|
||||
.
|
||||
)
|
||||
|
||||
set(CPACK_PROJECT_URL "https://github.com/gabime/spdlog")
|
||||
set(CPACK_PACKAGE_VENDOR "Gabi Melman")
|
||||
set(CPACK_PACKAGE_CONTACT "Gabi Melman <gmelman1@gmail.com>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Fast C++ logging library")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
if (PROJECT_VERSION_TWEAK)
|
||||
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK})
|
||||
endif ()
|
||||
set(CPACK_PACKAGE_RELOCATABLE ON CACHE BOOL "Build relocatable package")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries")
|
||||
set(CPACK_RPM_PACKAGE_URL ${CPACK_PROJECT_URL})
|
||||
set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.")
|
||||
|
||||
if (CPACK_PACKAGE_NAME)
|
||||
set(CPACK_RPM_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
else()
|
||||
set(CPACK_RPM_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
endif()
|
||||
|
||||
if (CPACK_RPM_PACKAGE_RELEASE)
|
||||
set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}-${CPACK_RPM_PACKAGE_RELEASE}")
|
||||
endif ()
|
||||
|
||||
if (CPACK_RPM_PACKAGE_ARCHITECTURE)
|
||||
set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.${CPACK_RPM_PACKAGE_ARCHITECTURE}")
|
||||
endif ()
|
||||
set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.rpm")
|
||||
|
||||
if (NOT CPACK_PACKAGE_RELOCATABLE)
|
||||
# Depend on pkgconfig rpm to create the system pkgconfig folder
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES pkgconfig)
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif ()
|
||||
|
||||
include(CPack)
|
15
third_party/spdlog/cmake/spdlogConfig.cmake.in
vendored
15
third_party/spdlog/cmake/spdlogConfig.cmake.in
vendored
@ -1,15 +0,0 @@
|
||||
# Copyright(c) 2019 spdlog authors
|
||||
# Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@)
|
||||
set(config_targets_file @config_targets_file@)
|
||||
|
||||
if(SPDLOG_FMT_EXTERNAL)
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(fmt CONFIG)
|
||||
endif()
|
||||
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/${config_targets_file}")
|
59
third_party/spdlog/cmake/utils.cmake
vendored
59
third_party/spdlog/cmake/utils.cmake
vendored
@ -1,59 +0,0 @@
|
||||
# Get spdlog version from include/spdlog/version.h and put it in SPDLOG_VERSION
|
||||
function(spdlog_extract_version)
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/include/spdlog/version.h" file_contents)
|
||||
string(REGEX MATCH "SPDLOG_VER_MAJOR ([0-9]+)" _ "${file_contents}")
|
||||
if(NOT CMAKE_MATCH_COUNT EQUAL 1)
|
||||
message(FATAL_ERROR "Could not extract major version number from spdlog/version.h")
|
||||
endif()
|
||||
set(ver_major ${CMAKE_MATCH_1})
|
||||
|
||||
string(REGEX MATCH "SPDLOG_VER_MINOR ([0-9]+)" _ "${file_contents}")
|
||||
if(NOT CMAKE_MATCH_COUNT EQUAL 1)
|
||||
message(FATAL_ERROR "Could not extract minor version number from spdlog/version.h")
|
||||
endif()
|
||||
|
||||
set(ver_minor ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "SPDLOG_VER_PATCH ([0-9]+)" _ "${file_contents}")
|
||||
if(NOT CMAKE_MATCH_COUNT EQUAL 1)
|
||||
message(FATAL_ERROR "Could not extract patch version number from spdlog/version.h")
|
||||
endif()
|
||||
set(ver_patch ${CMAKE_MATCH_1})
|
||||
|
||||
set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE)
|
||||
set(SPDLOG_VERSION_MINOR ${ver_minor} PARENT_SCOPE)
|
||||
set(SPDLOG_VERSION_PATCH ${ver_patch} PARENT_SCOPE)
|
||||
set (SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
# Turn on warnings on the given target
|
||||
function(spdlog_enable_warnings target_name)
|
||||
if(SPDLOG_BUILD_WARNINGS)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
list(APPEND MSVC_OPTIONS "/W3")
|
||||
if(MSVC_VERSION GREATER 1900) #Allow non fatal security wanrnings for msvc 2015
|
||||
list(APPEND MSVC_OPTIONS "/WX")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_options(${target_name} PRIVATE
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
|
||||
-Wall -Wextra -Wconversion -pedantic -Wfatal-errors>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:${MSVC_OPTIONS}>)
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
# Enable address sanitizer (gcc/clang only)
|
||||
function(spdlog_enable_sanitizer target_name)
|
||||
if (NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
message(FATAL_ERROR "Sanitizer supported only for gcc/clang")
|
||||
endif()
|
||||
message(STATUS "Address sanitizer enabled")
|
||||
target_compile_options(${target_name} PRIVATE -fsanitize=address,undefined)
|
||||
target_compile_options(${target_name} PRIVATE -fno-sanitize=signed-integer-overflow)
|
||||
target_compile_options(${target_name} PRIVATE -fno-sanitize-recover=all)
|
||||
target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer)
|
||||
target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined -fuse-ld=gold)
|
||||
endfunction()
|
42
third_party/spdlog/cmake/version.rc.in
vendored
42
third_party/spdlog/cmake/version.rc.in
vendored
@ -1,42 +0,0 @@
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0
|
||||
PRODUCTVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "spdlog dll\0"
|
||||
VALUE "FileVersion", "@SPDLOG_VERSION@.0\0"
|
||||
VALUE "InternalName", "spdlog.dll\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) spdlog\0"
|
||||
VALUE "ProductName", "spdlog\0"
|
||||
VALUE "ProductVersion", "@SPDLOG_VERSION@.0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
|
||||
|
||||
|
25
third_party/spdlog/example/CMakeLists.txt
vendored
25
third_party/spdlog/example/CMakeLists.txt
vendored
@ -1,25 +0,0 @@
|
||||
# Copyright(c) 2019 spdlog authors
|
||||
# Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(spdlog_examples CXX)
|
||||
|
||||
if(NOT TARGET spdlog)
|
||||
# Stand-alone build
|
||||
find_package(spdlog REQUIRED)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Example of using pre-compiled library
|
||||
#---------------------------------------------------------------------------------------
|
||||
add_executable(example example.cpp)
|
||||
target_link_libraries(example PRIVATE spdlog::spdlog)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
# Example of using header-only library
|
||||
#---------------------------------------------------------------------------------------
|
||||
if(SPDLOG_BUILD_EXAMPLE_HO)
|
||||
add_executable(example_header_only example.cpp)
|
||||
target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
|
||||
endif()
|
||||
|
282
third_party/spdlog/example/example.cpp
vendored
282
third_party/spdlog/example/example.cpp
vendored
@ -1,282 +0,0 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
// spdlog usage example
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
void load_levels_example();
|
||||
void stdout_logger_example();
|
||||
void basic_example();
|
||||
void rotating_example();
|
||||
void daily_example();
|
||||
void async_example();
|
||||
void binary_example();
|
||||
void trace_example();
|
||||
void multi_sink_example();
|
||||
void user_defined_example();
|
||||
void err_handler_example();
|
||||
void syslog_example();
|
||||
void custom_flags_example();
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/cfg/env.h" // for loading levels from the environment variable
|
||||
|
||||
int main(int, char *[])
|
||||
{
|
||||
// Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
|
||||
load_levels_example();
|
||||
|
||||
spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
|
||||
|
||||
spdlog::warn("Easy padding in numbers like {:08d}", 12);
|
||||
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||
spdlog::info("Support for floats {:03.2f}", 1.23456);
|
||||
spdlog::info("Positional args are {1} {0}..", "too", "supported");
|
||||
spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");
|
||||
|
||||
// Runtime log levels
|
||||
spdlog::set_level(spdlog::level::info); // Set global log level to info
|
||||
spdlog::debug("This message should not be displayed!");
|
||||
spdlog::set_level(spdlog::level::trace); // Set specific logger's log level
|
||||
spdlog::debug("This message should be displayed..");
|
||||
|
||||
// Customize msg format for all loggers
|
||||
spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v");
|
||||
spdlog::info("This an info message with custom format");
|
||||
spdlog::set_pattern("%+"); // back to default format
|
||||
spdlog::set_level(spdlog::level::info);
|
||||
|
||||
// Backtrace support
|
||||
// Loggers can store in a ring buffer all messages (including debug/trace) for later inspection.
|
||||
// When needed, call dump_backtrace() to see what happened:
|
||||
spdlog::enable_backtrace(10); // create ring buffer with capacity of 10 messages
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
spdlog::debug("Backtrace message {}", i); // not logged..
|
||||
}
|
||||
// e.g. if some error happened:
|
||||
spdlog::dump_backtrace(); // log them now!
|
||||
|
||||
try
|
||||
{
|
||||
stdout_logger_example();
|
||||
basic_example();
|
||||
rotating_example();
|
||||
daily_example();
|
||||
async_example();
|
||||
binary_example();
|
||||
multi_sink_example();
|
||||
user_defined_example();
|
||||
err_handler_example();
|
||||
trace_example();
|
||||
custom_flags_example();
|
||||
|
||||
// Flush all *registered* loggers using a worker thread every 3 seconds.
|
||||
// note: registered loggers *must* be thread safe for this to work correctly!
|
||||
spdlog::flush_every(std::chrono::seconds(3));
|
||||
|
||||
// Apply some function on all registered loggers
|
||||
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
|
||||
|
||||
// Release all spdlog resources, and drop all loggers in the registry.
|
||||
// This is optional (only mandatory if using windows + async log).
|
||||
spdlog::shutdown();
|
||||
}
|
||||
|
||||
// Exceptions will only be thrown upon failed logger or sink construction (not during logging).
|
||||
catch (const spdlog::spdlog_ex &ex)
|
||||
{
|
||||
std::printf("Log initialization failed: %s\n", ex.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
|
||||
void stdout_logger_example()
|
||||
{
|
||||
// Create color multi threaded logger.
|
||||
auto console = spdlog::stdout_color_mt("console");
|
||||
// or for stderr:
|
||||
// auto console = spdlog::stderr_color_mt("error-logger");
|
||||
}
|
||||
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
void basic_example()
|
||||
{
|
||||
// Create basic file logger (not rotated).
|
||||
auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt");
|
||||
}
|
||||
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
void rotating_example()
|
||||
{
|
||||
// Create a file rotating logger with 5mb size max and 3 rotated files.
|
||||
auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
|
||||
}
|
||||
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
void daily_example()
|
||||
{
|
||||
// Create a daily logger - a new file is created every day on 2:30am.
|
||||
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
|
||||
}
|
||||
|
||||
#include "spdlog/cfg/env.h"
|
||||
void load_levels_example()
|
||||
{
|
||||
// Set the log level to "info" and mylogger to to "trace":
|
||||
// SPDLOG_LEVEL=info,mylogger=trace && ./example
|
||||
spdlog::cfg::load_env_levels();
|
||||
// or from command line:
|
||||
// ./example SPDLOG_LEVEL=info,mylogger=trace
|
||||
// #include "spdlog/cfg/argv.h" // for loading levels from argv
|
||||
// spdlog::cfg::load_argv_levels(args, argv);
|
||||
}
|
||||
|
||||
#include "spdlog/async.h"
|
||||
void async_example()
|
||||
{
|
||||
// Default thread pool settings can be modified *before* creating the async logger:
|
||||
// spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
|
||||
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
|
||||
// alternatively:
|
||||
// auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
|
||||
|
||||
for (int i = 1; i < 101; ++i)
|
||||
{
|
||||
async_file->info("Async message #{}", i);
|
||||
}
|
||||
}
|
||||
|
||||
// Log binary data as hex.
|
||||
// Many types of std::container<char> types can be used.
|
||||
// Iterator ranges are supported too.
|
||||
// Format flags:
|
||||
// {:X} - print in uppercase.
|
||||
// {:s} - don't separate each byte with space.
|
||||
// {:p} - don't print the position on each line start.
|
||||
// {:n} - don't split the output to lines.
|
||||
|
||||
#include "spdlog/fmt/bin_to_hex.h"
|
||||
void binary_example()
|
||||
{
|
||||
std::vector<char> buf(80);
|
||||
for (int i = 0; i < 80; i++)
|
||||
{
|
||||
buf.push_back(static_cast<char>(i & 0xff));
|
||||
}
|
||||
spdlog::info("Binary example: {}", spdlog::to_hex(buf));
|
||||
spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
|
||||
// more examples:
|
||||
// logger->info("uppercase: {:X}", spdlog::to_hex(buf));
|
||||
// logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
|
||||
// logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
|
||||
// logger->info("hexdump style: {:a}", spdlog::to_hex(buf));
|
||||
// logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20));
|
||||
}
|
||||
|
||||
// Compile time log levels.
|
||||
// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)
|
||||
void trace_example()
|
||||
{
|
||||
// trace from default logger
|
||||
SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23);
|
||||
// debug from default logger
|
||||
SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23);
|
||||
|
||||
// trace from logger object
|
||||
auto logger = spdlog::get("file_logger");
|
||||
SPDLOG_LOGGER_TRACE(logger, "another trace message");
|
||||
}
|
||||
|
||||
// A logger with multiple sinks (stdout and file) - each with a different format and log level.
|
||||
void multi_sink_example()
|
||||
{
|
||||
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||
console_sink->set_level(spdlog::level::warn);
|
||||
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
|
||||
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
|
||||
file_sink->set_level(spdlog::level::trace);
|
||||
|
||||
spdlog::logger logger("multi_sink", {console_sink, file_sink});
|
||||
logger.set_level(spdlog::level::debug);
|
||||
logger.warn("this should appear in both console and file");
|
||||
logger.info("this message should not appear in the console, only in the file");
|
||||
}
|
||||
|
||||
// User defined types logging by implementing operator<<
|
||||
#include "spdlog/fmt/ostr.h" // must be included
|
||||
struct my_type
|
||||
{
|
||||
int i;
|
||||
template<typename OStream>
|
||||
friend OStream &operator<<(OStream &os, const my_type &c)
|
||||
{
|
||||
return os << "[my_type i=" << c.i << "]";
|
||||
}
|
||||
};
|
||||
|
||||
void user_defined_example()
|
||||
{
|
||||
spdlog::info("user defined type: {}", my_type{14});
|
||||
}
|
||||
|
||||
// Custom error handler. Will be triggered on log failure.
|
||||
void err_handler_example()
|
||||
{
|
||||
// can be set globally or per logger(logger->set_error_handler(..))
|
||||
spdlog::set_error_handler([](const std::string &msg) { printf("*** Custom log error handler: %s ***\n", msg.c_str()); });
|
||||
}
|
||||
|
||||
// syslog example (linux/osx/freebsd)
|
||||
#ifndef _WIN32
|
||||
#include "spdlog/sinks/syslog_sink.h"
|
||||
void syslog_example()
|
||||
{
|
||||
std::string ident = "spdlog-example";
|
||||
auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
|
||||
syslog_logger->warn("This is warning that will end up in syslog.");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Android example.
|
||||
#if defined(__ANDROID__)
|
||||
#include "spdlog/sinks/android_sink.h"
|
||||
void android_example()
|
||||
{
|
||||
std::string tag = "spdlog-android";
|
||||
auto android_logger = spdlog::android_logger_mt("android", tag);
|
||||
android_logger->critical("Use \"adb shell logcat\" to view this message.");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Log patterns can contain custom flags.
|
||||
// this will add custom flag '%*' which will be bound to a <my_formatter_flag> instance
|
||||
#include "spdlog/pattern_formatter.h"
|
||||
class my_formatter_flag : public spdlog::custom_flag_formatter
|
||||
{
|
||||
public:
|
||||
void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
|
||||
{
|
||||
std::string some_txt = "custom-flag";
|
||||
dest.append(some_txt.data(), some_txt.data() + some_txt.size());
|
||||
}
|
||||
|
||||
std::unique_ptr<custom_flag_formatter> clone() const override
|
||||
{
|
||||
return spdlog::details::make_unique<my_formatter_flag>();
|
||||
}
|
||||
};
|
||||
|
||||
void custom_flags_example()
|
||||
{
|
||||
|
||||
using spdlog::details::make_unique; // for pre c++14
|
||||
auto formatter = make_unique<spdlog::pattern_formatter>();
|
||||
formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
|
||||
spdlog::set_formatter(std::move(formatter));
|
||||
}
|
4
third_party/spdlog/example/meson.build
vendored
4
third_party/spdlog/example/meson.build
vendored
@ -1,4 +0,0 @@
|
||||
executable('example', 'example.cpp', dependencies: spdlog_dep)
|
||||
executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep)
|
||||
|
||||
|
93
third_party/spdlog/include/spdlog/async.h
vendored
93
third_party/spdlog/include/spdlog/async.h
vendored
@ -1,93 +0,0 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Async logging using global thread pool
|
||||
// All loggers created here share same global thread pool.
|
||||
// Each log message is pushed to a queue along with a shared pointer to the
|
||||
// logger.
|
||||
// If a logger deleted while having pending messages in the queue, it's actual
|
||||
// destruction will defer
|
||||
// until all its messages are processed by the thread pool.
|
||||
// This is because each message in the queue holds a shared_ptr to the
|
||||
// originating logger.
|
||||
|
||||
#include <spdlog/async_logger.h>
|
||||
#include <spdlog/details/registry.h>
|
||||
#include <spdlog/details/thread_pool.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
namespace details {
|
||||
static const size_t default_async_q_size = 8192;
|
||||
}
|
||||
|
||||
// async logger factory - creates async loggers backed with thread pool.
|
||||
// if a global thread pool doesn't already exist, create it with default queue
|
||||
// size of 8192 items and single thread.
|
||||
template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
|
||||
struct async_factory_impl
|
||||
{
|
||||
template<typename Sink, typename... SinkArgs>
|
||||
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args)
|
||||
{
|
||||
auto ®istry_inst = details::registry::instance();
|
||||
|
||||
// create global thread pool if not already exists..
|
||||
|
||||
auto &mutex = registry_inst.tp_mutex();
|
||||
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
|
||||
auto tp = registry_inst.get_tp();
|
||||
if (tp == nullptr)
|
||||
{
|
||||
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1);
|
||||
registry_inst.set_tp(tp);
|
||||
}
|
||||
|
||||
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
|
||||
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);
|
||||
registry_inst.initialize_logger(new_logger);
|
||||
return new_logger;
|
||||
}
|
||||
};
|
||||
|
||||
using async_factory = async_factory_impl<async_overflow_policy::block>;
|
||||
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
|
||||
|
||||
template<typename Sink, typename... SinkArgs>
|
||||
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args)
|
||||
{
|
||||
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
|
||||
}
|
||||
|
||||
template<typename Sink, typename... SinkArgs>
|
||||
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&... sink_args)
|
||||
{
|
||||
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
|
||||
}
|
||||
|
||||
// set global thread pool.
|
||||
inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start)
|
||||
{
|
||||
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start);
|
||||
details::registry::instance().set_tp(std::move(tp));
|
||||
}
|
||||
|
||||
// set global thread pool.
|
||||
inline void init_thread_pool(size_t q_size, size_t thread_count)
|
||||
{
|
||||
init_thread_pool(q_size, thread_count, [] {});
|
||||
}
|
||||
|
||||
// get the global thread pool.
|
||||
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool()
|
||||
{
|
||||
return details::registry::instance().get_tp();
|
||||
}
|
||||
} // namespace spdlog
|
@ -1,92 +0,0 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/async_logger.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/details/thread_pool.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
SPDLOG_INLINE spdlog::async_logger::async_logger(
|
||||
std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)
|
||||
{}
|
||||
|
||||
SPDLOG_INLINE spdlog::async_logger::async_logger(
|
||||
std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||
: async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)
|
||||
{}
|
||||
|
||||
// send the log message to the thread pool
|
||||
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg)
|
||||
{
|
||||
if (auto pool_ptr = thread_pool_.lock())
|
||||
{
|
||||
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
|
||||
}
|
||||
}
|
||||
|
||||
// send flush request to the thread pool
|
||||
SPDLOG_INLINE void spdlog::async_logger::flush_()
|
||||
{
|
||||
if (auto pool_ptr = thread_pool_.lock())
|
||||
{
|
||||
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// backend functions - called from the thread pool to do the actual job
|
||||
//
|
||||
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg)
|
||||
{
|
||||
for (auto &sink : sinks_)
|
||||
{
|
||||
if (sink->should_log(msg.level))
|
||||
{
|
||||
SPDLOG_TRY
|
||||
{
|
||||
sink->log(msg);
|
||||
}
|
||||
SPDLOG_LOGGER_CATCH()
|
||||
}
|
||||
}
|
||||
|
||||
if (should_flush_(msg))
|
||||
{
|
||||
backend_flush_();
|
||||
}
|
||||
}
|
||||
|
||||
SPDLOG_INLINE void spdlog::async_logger::backend_flush_()
|
||||
{
|
||||
for (auto &sink : sinks_)
|
||||
{
|
||||
SPDLOG_TRY
|
||||
{
|
||||
sink->flush();
|
||||
}
|
||||
SPDLOG_LOGGER_CATCH()
|
||||
}
|
||||
}
|
||||
|
||||
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
|
||||
{
|
||||
auto cloned = std::make_shared<spdlog::async_logger>(*this);
|
||||
cloned->name_ = std::move(new_name);
|
||||
return cloned;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user